Go đối số chức năng được truyền theo giá trị.
Trước 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 thấy rằng bạn chỉ đang truyề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)
}
Output:
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 chức năng main
, i
là một biến int
tại vị trí bộ nhớ (&i
) 0xf800000040
với giá trị ban đầu (i
) 42
.
Trong chức năng main
, p
là một con trỏ đến một biến int
tại vị trí bộ nhớ (&p
) 0xf8000000f0
với một giá trị (p
= &i
) 0xf800000040
mà trỏ đến một giá trị int
(*p
= i
) 42
.
Trong chức năng main
, byval(p)
là một cuộc gọi chức năng mà gán giá trị (p
= &i
) 0xf800000040
của đối số tại vị trí bộ nhớ (&p
) 0xf8000000f0
đến chức năng byval
tham số q
tại vị trí bộ nhớ (&q
) 0xf8000000d8
. Nói cách khác, bộ nhớ được phân bổ cho thông số byval
q
và giá trị của đối số main
byval
đượ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 số p
và q
là khác biệt.
Trong chức năng byval
, sử dụng con trỏ q
(*int
), mà là một bản sao của con trỏ p
(*int
), số nguyên *q
(i
) được đặt thành một giá trị int mới 4143
. Cuối cùng trước khi trở về. con trỏ q
được đặt thành nil
(giá trị bằng không), không ảnh hưởng đến p
kể từ q
là bản sao.
Trong chức năng main
, p
là một con trỏ đến một biến int
tại vị trí bộ nhớ (&p
) 0xf8000000f0
với một giá trị (p
= &i
) 0xf800000040
mà trỏ đến một giá trị mới int
(*p
= i
) 4143
.
Trong chức năng main
, i
là một biến int
tại vị trí bộ nhớ (&i
) 0xf800000040
với một giá trị cuối cùng (i
) 4143
.
Trong ví dụ của bạn, chức năng main
biến s
sử dụng như một tham số để gọi hàm gotest
không giống như chức năng gotest
tham số s
. Họ có cùng tên, nhưng là các biến khác nhau với phạm vi và vị trí bộ nhớ khác nhau. Tham số chức năng s
ẩn đối số cuộc 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à 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 địa điểm bộ nhớ cho biến s
chức năng main
được sử dụng như một đối số cho hàm gọi gotest(s, done)
, và 0x4974d8
là địa chỉ của địa điểm bộ nhớ cho các chức năng gotest
tham số s
. Nếu bạn đặt tham số s = nil
ở cuối hàm gotest
, nó không có hiệu lực trên biến s
trong main
; s
trong main
và s
trong gotest
là các vị trí bộ nhớ riêng biệt. Về loại, &s
là **Something
, s
là *Something
và *s
là Something
. &s
là một con trỏ đến (địa chỉ của vị trí bộ nhớ) s
, là một con trỏ đến (địa chỉ của vị trí bộ nhớ) một biến ẩn danh của loại Something
. 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 tham khảo ý kiến hiền triết của mkb và ngừng sử dụng println(&s)
. Sử dụng gói fmt
, ví dụ:
fmt.Printf("%v %p %v\n", &s, s, *s)
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.
Trong ví dụ của tôi, gotest lấy một con trỏ đến 'Something' vì vậy tôi giả định nó được đề cập đến cùng một đối tượng và rõ ràng là kể từ sau khi tôi thay đổi giá trị bên trong đi-thường xuyên đối tượng cũng có giá trị của nó thay đổi trong chính chức năng. Giá trị con trỏ được in khác nhau. –
@JamesDean Trong ví dụ của bạn, bạn đang in giá trị con trỏ & s loại ** Một cái gì đó, mà không phải là giống như giá trị con trỏ s * Một cái gì đó. Tôi đã sửa đổi ví dụ của mình để chuyển một con trỏ theo giá trị. – peterSO
@James Dean Bạn đã in ra địa chỉ của con trỏ (tức là con trỏ tới con trỏ 's'), - con trỏ được truyền theo giá trị, địa chỉ của' s' không giống với 's'. Nếu hàm getest của bạn có 'println (s)' intead, nó sẽ in giá trị con trỏ. – nos