2011-02-08 88 views
43

Tôi chỉ chơi đùa với Go và chưa có mô hình tinh thần tốt khi cấu trúc được truyền theo giá trị hoặc tham chiếu.Làm cách nào để in giá trị con trỏ của đối tượng Go? Giá trị con trỏ có ý nghĩa gì?

Đây có thể là một câu hỏi rất câm nhưng tôi chỉ muốn thử nghiệm một chút và xem tôi vẫn đang làm việc trên cùng một đối tượng hay tôi đã tạo một bản sao của nó (chuyển nó theo giá trị).

Có cách nào để in con trỏ (hoặc id nội bộ nếu giá trị con trỏ bị thay đổi bởi gc) của một đối tượng không?

package main 

import ("runtime") 

type Something struct { 
    number int 
    queue chan int 
} 

func gotest(s *Something, done chan bool) { 
    println("from gotest:") 
    println(&s) 
    for num := range s.queue { 
     println(num) 
     s.number = num 
    } 
    done <- true 
} 

func main() { 
    runtime.GOMAXPROCS(4) 
    s := new(Something) 
    println(&s) 
    s.queue = make(chan int) 
    done := make(chan bool) 
    go gotest(s, done) 
    s.queue <- 42 
    close(s.queue) 
    <- done 
    println(&s) 
    println(s.number) 
} 

cho trên cửa sổ của tôi (8g phiên bản biên soạn):

0x4930d4 
from gotest: 
0x4974d8 
42 
0x4930d4 
42 

Tại sao giá trị con trỏ từ bên trong đi diễn thường xuyên một giá trị khác nhau? Số lượng trên đối tượng ban đầu đã được thay đổi để nó làm việc với cùng một đối tượng. Có cách nào để xem id đối tượng liên tục không?

Trả lời

51

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ố byvalq và giá trị của đối số mainbyval được gán cho nó; các giá trị của pq ban đầu giống nhau, nhưng các biến số pq 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ố pq 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 mains trong gotest là các vị trí bộ nhớ riêng biệt. Về loại, &s**Something, s*Something*sSomething. &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.*smain.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.

+0

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. –

+0

@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

+0

@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

1
type sometype struct { } 
a := sometype {} 
b := int(2) 
println("Ptr to a", &a) 
println("Ptr to b", &b) 
+4

Bạn không nên sử dụng println dựng sẵn nhưng sử dụng một cái gì đó thích hợp từ gói fmt: http: // golang .org/doc/go_spec.html # Bootstrapping – mkb

5

Khi đến, đối số được chuyển theo giá trị.

package main 

import "fmt" 

type SomeStruct struct { 
    e int 
} 

// struct passed by value 
func v(v SomeStruct) { 
    fmt.Printf("v: %p %v\n", &v, v) 
    v.e = 2 
    fmt.Printf("v: %p %v\n", &v, v) 
} 

// pointer to struct passed by value 
func p(p *SomeStruct) { 
    fmt.Printf("p: %p %v\n", p, *p) 
    p.e = 2 
    fmt.Printf("p: %p %v\n", p, *p) 
} 

func main() { 
    var s SomeStruct 
    s.e = 1 
    fmt.Printf("s: %p %v\n", &s, s) 
    v(s) 
    fmt.Printf("s: %p %v\n", &s, s) 
    p(&s) 
    fmt.Printf("s: %p %v\n", &s, s) 
} 

Output:

s: 0xf800000040 {1} 
v: 0xf8000000e0 {1} 
v: 0xf8000000e0 {2} 
s: 0xf800000040 {1} 
p: 0xf800000040 {1} 
p: 0xf800000040 {2} 
s: 0xf800000040 {2} 
+0

Điều này có vẻ không đúng, tại sao tôi không thể chuyển con trỏ? 'func f (s * SomeStruct) {' –

+0

@MattJoiner: Đúng vậy. Bạn có thể vượt qua một con trỏ. Tôi đã sửa đổi ví dụ để cho bạn thấy làm thế nào. – peterSO

+0

Ngôn ngữ này có tiềm năng nghiêm trọng. –

1
package main 

import "fmt" 

func zeroval(ival int) { 
    ival = 0 
} 

func zeroptr(iptr *int) { 
    *iptr = 0 
} 

func main() { 
    i := 1 
    fmt.Println("initial:", i) 
    zeroval(i) 
    fmt.Println("zeroval:", i) 
    //The &i syntax gives the memory address of i, i.e. a pointer to i. 
    zeroptr(&i) 
    fmt.Println("zeroptr:", i) 
    //Pointers can be printed too. 
    fmt.Println("pointer:", &i) 
} 

OUTPUT:

$ go run pointers.go 
initial: 1 
zeroval: 1 
zeroptr: 0 
pointer: 0x42131100 
1

Làm thế nào để print giá trị con trỏ của một đối tượng Go?

package main 

import (
    "fmt" 
) 

func main() { 
    a := 42 
    fmt.Println(&a) 
} 

kết quả trong:

0x1040a124 

không giá trị con trỏ nghĩa là gì?

Theo Wikipedia:

Một con trỏ tham chiếu đến một vị trí trong bộ nhớ

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