Các đối số của hàm Go được truyền theo giá trị.
Đầu tiên, hãy loại bỏ các phần không liên quan trong ví dụ của bạn, để chúng tôi có thể dễ dàng nhận thấy rằng bạn chỉ đang chuyển một đối số theo giá trị. Ví dụ,
package main
import "fmt"
func byval(q *int) {
fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
*q = 4143
fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
q = nil
}
func main() {
i := int(42)
fmt.Printf("1. main -- i %T: &i=%p i=%v\n", i, &i, i)
p := &i
fmt.Printf("2. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
byval(p)
fmt.Printf("5. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
fmt.Printf("6. main -- i %T: &i=%p i=%v\n", i, &i, i)
}
Đầu ra:
1. main -- i int: &i=0xf840000040 i=42
2. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=4143
5. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=4143
6. main -- i int: &i=0xf840000040 i=4143
Trong hàm main, ilà một intbiến tại vị trí bộ nhớ ( &i) 0xf800000040với giá trị ban đầu ( i) 42.
Trong hàm main, plà một con trỏ đến một intbiến tại vị trí bộ nhớ ( &p) 0xf8000000f0với giá trị ( p= &i) 0xf800000040trỏ đến intgiá trị ( *p= i) 42.
Trong hàm main, byval(p)là một lệnh gọi hàm gán giá trị ( p= &i) 0xf800000040của đối số tại vị trí bộ nhớ ( &p) 0xf8000000f0cho byvaltham số hàm qtại vị trí bộ nhớ ( &q) 0xf8000000d8. Nói cách khác, bộ nhớ được cấp phát cho byvaltham số qvà giá trị của main byvalđối số pđược gán cho nó; các giá trị của pvà qban đầu giống nhau, nhưng các biến pvà qkhác nhau.
Trong hàm byval, sử dụng pointer q( *int), là bản sao của pointer p( *int), integer *q( i) được đặt thành giá trị int mới 4143. Vào cuối trước khi trở lại. con trỏ qđược đặt thành nil(giá trị 0), không ảnh hưởng đến pvì qlà một bản sao.
Trong hàm main, plà một con trỏ đến một intbiến tại vị trí bộ nhớ ( &p) 0xf8000000f0với giá trị ( p= &i) 0xf800000040trỏ đến intgiá trị mới ( *p= i) 4143.
Trong hàm main, ilà một intbiến tại vị trí bộ nhớ ( &i) 0xf800000040với giá trị cuối cùng ( i) 4143.
Trong ví dụ của bạn, mainbiến hàm sđược sử dụng làm đối số cho lệnh gotestgọi hàm không giống với gotesttham số hàm s. Chúng có cùng tên, nhưng là các biến khác nhau với các phạm vi và vị trí bộ nhớ khác nhau. Tham số hàm sẩn đối số gọi hàm s. Đó là lý do tại sao trong ví dụ của tôi, tôi đặt tên cho đối số và các biến tham số pvà qtương ứng để nhấn mạnh sự khác biệt.
Trong ví dụ của bạn, ( &s) 0x4930d4là địa chỉ của vị trí bộ nhớ cho biến strong hàm mainđược sử dụng làm đối số cho lệnh gọi hàm gotest(s, done)và 0x4974d8là địa chỉ của vị trí bộ nhớ cho gotesttham số hàm s. Nếu bạn đặt tham số s = nilở cuối hàm gotest, nó không ảnh hưởng đến biến strong main; strong mainvà strong gotestlà các vị trí bộ nhớ riêng biệt. Xét về các loại, &sis **Something, sis *Something, and *sis Something. &slà một con trỏ tới (địa chỉ của vị trí bộ nhớ) s, là một con trỏ tới (địa chỉ của vị trí bộ nhớ) một biến ẩn danh kiểuSomething. Xét về giá trị, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s, và main.s.number == gotest.s.number.
Bạn nên nghe theo lời khuyên của mkb's sage và ngừng sử dụng println(&s). fmtVí dụ: sử dụng gói,
fmt.Printf("%v %p %v\n", &s, s, *s)
Các con trỏ có cùng giá trị khi chúng trỏ đến cùng một vị trí bộ nhớ; con trỏ có các giá trị khác nhau khi chúng trỏ đến các vị trí bộ nhớ khác nhau.