2010-05-02 34 views

Trả lời

5

Nếu bạn khai báo hoặc phân bổ biến số type bar, bạn đặt trước và khởi tạo bộ nhớ bằng không cho cả rd uint8foo foo_. Luôn có một biến số type foo_ được nhúng trong biến số type bar.

var b bar // declare b 

Nếu bạn khai báo hoặc phân bổ một biến type barP, bạn dự trữ và khởi tạo vào bộ nhớ zero cho cả rd uint8foo *foo_. Con trỏ giá trị bằng không là con trỏ nil. Không có biến nào của type foo_ được phân bổ; bạn phải làm điều đó một cách riêng biệt. Có một số không (foo == nil) hoặc một biến số type foo_ được trỏ đến bởi một biến số type barP. Biến số type barP có thể trỏ đến cùng một biến số type foo_ dưới dạng các biến số khác của type barP, chia sẻ cùng một bản sao của biến số type foo_. Một thay đổi đối với một bản sao được chia sẻ được nhìn thấy bởi tất cả các biến trỏ đến nó.

var bp barP   // declare bp 
bp.foo = new(foo_) // allocate bp.foo 

Mà một trong những sử dụng phụ thuộc vào các tính chất của type bar so type barP. Loại nào phản ánh chặt chẽ hơn vấn đề mà bạn đang cố giải quyết?

Ví dụ: xem xét vấn đề hóa đơn này. Chúng tôi luôn có địa chỉ thanh toán; chúng tôi luôn đòi tiền của chúng tôi. Tuy nhiên, chúng tôi thường gửi đến địa chỉ thanh toán, nhưng không phải lúc nào. Nếu địa chỉ giao hàng là nil, hãy sử dụng địa chỉ thanh toán. Nếu không, hãy sử dụng địa chỉ giao hàng riêng. Chúng tôi có hai nhà kho, và chúng tôi luôn luôn vận chuyển từ một hoặc khác. Chúng tôi có thể chia sẻ hai địa điểm kho. Vì chúng tôi không gửi hóa đơn cho đến khi đơn đặt hàng được gửi từ nhà kho, vị trí nhà kho sẽ không bao giờ là nil.

type address struct { 
    street string 
    city string 
} 

type warehouse struct { 
    address string 
} 

type invoice struct { 
    name  string 
    billing address 
    shipping *address 
    warehouse *warehouse 
} 
2

Câu trả lời phần lớn độc lập với ngôn ngữ - tương đương trong C có cùng vấn đề.

Khi bạn có giá trị được nhúng (như trong bar), thì cấu trúc của bạn đủ lớn để giữ cấu trúc con hoàn chỉnh và phần còn lại.

Khi bạn có con trỏ đến giá trị (như trong barP), thì một số cấu trúc thuộc loại barP có thể chia sẻ cùng một foo. Khi bất kỳ số nào trong số barP sửa đổi một phần của foo nó trỏ đến, nó ảnh hưởng đến tất cả các cấu trúc khác barP trỏ đến cùng một vị trí. Ngoài ra, như bình luận cho thấy, bạn phải quản lý hai đối tượng riêng biệt - các barPfoo như chống lại một với các loại đồng bằng bar.

Trong một số ngôn ngữ, bạn sẽ phải lo lắng về các con trỏ lơ lửng và các giá trị chưa được khởi tạo vv; Go là rác được thu thập và thường loại an toàn hơn các ngôn ngữ khác.

Vì vậy, hãy sử dụng con trỏ khi bạn muốn nhiều đối tượng barP để chia sẻ cùng một đối tượng foo; nếu không, sử dụng một đối tượng thành viên rõ ràng, chứ không phải là một con trỏ tới một đối tượng.

+1

Khi biến 'loại barP' được khai báo hoặc cấp phát, giá trị ban đầu của foo sẽ là con trỏ' nil'. – peterSO

2

Các Golang FAQ nay tóm tắt sự khác biệt giữa:

func (s *MyStruct) pointerMethod() { } // method on pointer 
func (s MyStruct) valueMethod() { } // method on value 

Thứ nhất, và quan trọng nhất, làm phương pháp này cần phải sửa đổi nhận?
Nếu có, người nhận phải là con trỏ. (Slices và maps là các kiểu tham chiếu, vì vậy câu chuyện của chúng hơi phức tạp hơn, nhưng ví dụ để thay đổi độ dài của một slice trong một phương thức, người nhận vẫn phải là một con trỏ.)
Trong các ví dụ trên, nếu pointerMethod sửa đổi các trường của s, người gọi sẽ thấy những thay đổi đó, nhưng valueMethod được gọi với một bản sao của đối số của người gọi (đó là định nghĩa truyền giá trị), vì vậy những thay đổi mà nó thực hiện sẽ không hiển thị với người gọi.
Nhân tiện, các trình thu nhận con trỏ giống hệt với tình huống trong Java, mặc dù trong Java, các con trỏ được ẩn dưới các bìa; đó là các máy thu giá trị của Go mà không bình thường.

Thứ hai là xem xét hiệu quả. Nếu người nhận là lớn, một cấu trúc lớn ví dụ, nó sẽ rẻ hơn nhiều để sử dụng một máy thu con trỏ.

(điểm hiệu quả này cũng được minh họa trong "Memory, variables in memory, and pointers")

Tiếp theo là quán. Nếu một số phương thức của loại phải có bộ thu con trỏ, phần còn lại cũng nên, vì vậy tập hợp phương thức nhất quán bất kể loại được sử dụng như thế nào. Xem phần trên method sets để biết chi tiết.

Các vấn đề liên quan