2013-02-26 29 views
19

Tôi hiện đang học lập trình bằng ngôn ngữ Go. Tôi đang gặp một số khó khăn trong việc tìm hiểu các con trỏ đi (và C/C++ của tôi ở rất xa bây giờ ...). Trong Tour của Go # 52 (http://tour.golang.org/#52) ví dụ, tôi đọc:Con trỏ Golang

type Vertex struct { 
    X, Y float64 
} 

func (v *Vertex) Abs() float64 { 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

func main() { 
    v := &Vertex{3, 4} 
    fmt.Println(v.Abs()) 
} 

Nhưng nếu thay vì

tôi đã viết:

func (v Vertex) Abs() float64 { 
[...] 
v := Vertex{3, 4} 

Hoặc thậm chí:

func (v Vertex) Abs() float64 { 
[...] 
v := &Vertex{3, 4} 

và ngược lại:

func (v *Vertex) Abs() float64 { 
[...] 
v := Vertex{3, 4} 

Tôi nhận được kết quả tương tự. Có một sự khác biệt (trí nhớ, khôn ngoan, vv)?

+2

Xin chào và chào mừng bạn đến với các lập trình viên. Các câu hỏi triển khai trực tiếp, chẳng hạn như đây là những chủ đề không có chủ đề ở đây nhưng về chủ đề về Stack Overflow. Tôi sẽ bắt đầu di chuyển. Có một ngày dễ chịu. –

+2

Hãy thử thay đổi 'v' trong tất cả các phương thức, và sau đó là' fmt.Println() 'bản gốc sau cuộc gọi, và bạn sẽ thấy sự khác biệt. Với các phiên bản '(v Vertex)', bạn sẽ nhận được một bản sao của bản gốc. Nếu nó được gọi là trên một con trỏ, nó chỉ dereferenced cho bạn tự động. –

+1

Xem thêm: [Phương thức nhận sự mơ hồ] (http://stackoverflow.com/questions/14926860/method-receivers-ambiguity) –

Trả lời

31

Có hai quy tắc khác nhau của ngôn ngữ được sử dụng bởi Go ví dụ của bạn:

  1. Có thể lấy được một phương pháp với một máy thu con trỏ từ một phương thức với một máy thu giá trị. Như vậy func (v Vertex) Abs() float64 sẽ tự động tạo ra một thực hiện phương pháp bổ sung:

    func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) } 
    func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) } // GENERATED METHOD 
    

    Trình biên dịch sẽ tự động tìm ra phương pháp tạo ra:

    v := &Vertex{3, 4} 
    v.Abs() // calls the generated method 
    
  2. Go có thể tự động lấy địa chỉ của một biến.Trong ví dụ sau:

    func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) } 
    func main() { 
        v := Vertex{3, 4} 
        v.Abs() 
    } 
    

    biểu thức v.Abs() tương đương với đoạn mã sau:

    vp := &v 
    vp.Abs() 
    
+0

Việc thực hiện * v có tạo bản sao v trong bộ nhớ (Vertex struct) không? Nếu không thì thực hiện thay đổi trong v trong khi thực thi func (v Vertex) Abs() phản ánh bên ngoài? – MaX

+2

Bản sao mới của struct Vertex được tạo trước khi nhập 'func (v Vertex) Abs()'. –

+1

@Atom Không chính xác hơn khi viết trong trường hợp đầu tiên, khi struct Vertex được sao chép trước khi nhập 'func (v Vertex) Abs()': 'func (v * Vertex) Abs() float64 {return (* v) .Abs()} // PHƯƠNG PHÁP CHUNG? Tôi đang gặp sự cố khi hiểu Vertex.Abs (* v) ... – eAbi

2

Sự khác biệt là tính năng tham chiếu chéo và giá trị chuyển đổi theo giá trị.

Trong func f(v Vertex) đối số là được sao chép thành thông số v. Trong func f(v *Vertex) một con trỏ tới phiên bản hiện tại Vertex được chuyển.

Khi sử dụng các phương pháp, một số cuộc hội thảo có thể được thực hiện cho bạn, vì vậy bạn có thể có phương thức func (v *Vertex) f() và gọi nó mà không cần dùng con trỏ trước: v := Vertex{...}; v.f(). Đây chỉ là một hạt đường cú pháp, AFAIK.

13

Có sự khác biệt. Ví dụ, biểu mẫu không nhận con trỏ buộc phương thức làm việc trên một bản sao. Bằng cách này, phương thức này không thể thay đổi được cá thể mà nó được gọi lên - nó chỉ có thể truy cập vào bản sao. Điều này có thể không hiệu quả về mặt, ví dụ: thời gian/hiệu năng bộ nhớ/tiêu thụ, vv

OTOH, con trỏ đến trường và phương pháp với thu con trỏ cho phép dễ dàng chia sẻ (và đột biến) Ví dụ nơi mong muốn.

Chi tiết khác here.

0

Có hai khác biệt chính trong những ví dụ:

func (v *Vertex) Abs().... 

Người nhận sẽ là được thông qua bởi tham chiếu cho v và bạn sẽ có thể gọi phương pháp này chỉ trên con trỏ:

v := Vertex{1,3} 
v.Abs() // This will result in compile time error 
&v.Abs() // But this will work 

Mặt khác

func (v Vertex) Abs() .... 

Bạn có thể gọi phương pháp này trên cả hai con trỏ và cấu trúc. Người nhận sẽ là được chuyển qua giá trị ngay cả khi bạn gọi phương thức này trên con trỏ.

v := Vertex{1,3} 
v.Abs() // This will work, v will be copied. 
&v.Abs() // This will also work, v will also be copied. 

Bạn có thể khai báo cả hai số func (v *Vertex)func (v Vertex).

0

Là đặc điểm kỹ thuật nói

Một x.m gọi phương thức() là hợp lệ nếu các thiết lập phương pháp (các loại) x chứa m và danh sách đối số có thể được gán vào danh sách tham số của m. Nếu x là địa chỉ và phương thức thiết lập & x chứa m, xm() là viết tắt cho (& x) .m():

Trong trường hợp v.Abs của bạn() là viết tắt cho & v.Abs() nếu phương thức là địa chỉ.