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
, i
là một int
biến tại vị trí bộ nhớ ( &i
) 0xf800000040
với giá trị ban đầu ( i
) 42
.
Trong hàm main
, p
là một con trỏ đến một int
biến tại vị trí bộ nhớ ( &p
) 0xf8000000f0
với giá trị ( p
= &i
) 0xf800000040
trỏ đến int
giá 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
) 0xf800000040
của đối số tại vị trí bộ nhớ ( &p
) 0xf8000000f0
cho byval
tham số hàm q
tại vị trí bộ nhớ ( &q
) 0xf8000000d8
. Nói cách khác, bộ nhớ được cấp phát cho byval
tham số q
và giá trị của main
byval
đối số p
được gán cho nó; các giá trị của p
và q
ban đầu giống nhau, nhưng các biến p
và q
khá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 p
vì q
là một bản sao.
Trong hàm main
, p
là một con trỏ đến một int
biến tại vị trí bộ nhớ ( &p
) 0xf8000000f0
với giá trị ( p
= &i
) 0xf800000040
trỏ đến int
giá trị mới ( *p
= i
) 4143
.
Trong hàm main
, i
là một int
biến tại vị trí bộ nhớ ( &i
) 0xf800000040
với giá trị cuối cùng ( i
) 4143
.
Trong ví dụ của bạn, main
biến hàm s
được sử dụng làm đối số cho lệnh gotest
gọi hàm không giống với gotest
tham 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ố p
và q
tương ứng để nhấn mạnh sự khác biệt.
Trong ví dụ của bạn, ( &s
) 0x4930d4
là địa chỉ của vị trí bộ nhớ cho biến s
trong hàm main
được sử dụng làm đối số cho lệnh gọi hàm gotest(s, done)
và 0x4974d8
là địa chỉ của vị trí bộ nhớ cho gotest
tham 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 s
trong main
; s
trong main
và s
trong gotest
là các vị trí bộ nhớ riêng biệt. Xét về các loại, &s
is **Something
, s
is *Something
, and *s
is Something
. &s
là 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)
. fmt
Ví 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.