2011-02-08 58 views
43

我只是在圍繞Go進行遊戲,並且還沒有一個好的心智模型,當結構按值或通過引用傳遞時。如何打印Go對象的指針值?指針值是什麼意思?

這可能是一個非常愚蠢的問題,但我只是想實驗一下,看看我是否仍在使用同一個對象,或者我已經制作了它的副本(通過值傳遞它)。

有沒有辦法打印指針(或內部ID,如果指針值被gc改變)的對象?

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) 
} 

在我的窗戶給人(8G編譯版本):

0x4930d4 
from gotest: 
0x4974d8 
42 
0x4930d4 
42 

爲什麼從內部指針值去日常表現出不同的價值?原始對象上的數量確實發生了變化,因此它使用同一個對象。有沒有辦法看到持久性的對象ID?

回答

51

轉到函數的參數是按值傳遞。

首先,讓我們放棄您示例中不相關的部分,以便我們可以輕鬆地看到您僅僅通過值傳遞參數。例如,

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) 
} 

輸出:

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 

在功能maini是在存儲器位置(&i0xf800000040與初始值(i42一個int變量。

在功能mainp是一個指針,指向在存儲位置(&p0xf8000000f0用一個值(p = &i0xf800000040它指向一個int值(*p = i42一個int變量。

在功能mainbyval(p)是一個函數調用,它在存儲位置(&q0xf8000000d8的值(p = &i)在存儲位置(&p0xf8000000f0參數的0xf800000040分配給功能byval參數q。換句話說,爲byval參數q分配了存儲空間,併爲其分配了參數pmainbyval值; pq的值最初是相同的,但變量pq是不同的。

在功能byval,使用指針q*int),這是指針p*int)的副本,整數*qi)被設定爲一個新的int值4143。在返回之前結束。指針q設置爲nil(零值),這對p沒有影響,因爲q是副本。

在功能mainp是一個指針,指向在存儲位置(&p0xf8000000f0用一個值(p = &i0xf800000040指向新int值(*p = i4143一個int變量。

在功能maini是在存儲器位置(&i0xf800000040與最終值(i4143一個int變量。

在您的例子中,函數main可變s用作的一個參數函數gotest呼叫不是一樣的功能gotest參數s。它們具有相同的名稱,但具有不同範圍和內存位置的不同變量。函數參數s隱藏函數調用參數s。這就是爲什麼在我的例子中,我分別命名參數和參數變量pq以強調這種差異。

在您的例子,(&s0x4930d4是用於功能main可變s被用作一個參數的函數調用gotest(s, done)的存儲器位置的地址,並且0x4974d8是的存儲器位置的該函數的地址gotest參數s。如果在功能gotest的末尾設置參數s = nil,則它對main中的變量s沒有影響; smainsgotest是不同的存儲位置。根據類型,&s**Somethings*Something,並且*sSomething&s是指向(存儲器位置的地址)s的指針,它是指向(存儲器位置的地址)類型Something的匿名變量的指針。根據數值,main.&s != gotest.&s,main.s == gotest.s,main.*s == gotest.*smain.s.number == gotest.s.number

你應該採取mkb的賢者的建議,並停止使用println(&s)。使用fmt包,例如,

fmt.Printf("%v %p %v\n", &s, s, *s) 

指針具有相同的值時,它們指向相同的內存位置;當指針指向不同的內存位置時,指針具有不同的值。

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

你不應該使用內置的println而是用一些適當從FMT包:HTTP:// golang .org/doc/go_spec.html#引導 – mkb 2011-02-09 02:30:28

5

在Go中,參數是按值傳遞的。

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) 
} 

輸出:

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

這看起來不正確,爲什麼我不能傳遞指針? `func f(s * SomeStruct){` – 2011-02-09 00:46:56

+0

@MattJoiner:是的。你可以傳遞一個指針。我已經修改了這個例子來向你展示如何。 – peterSO 2011-02-09 02:24:25

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

如何print一個圍棋對象的指針值?

package main 

import (
    "fmt" 
) 

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

結果:

0x1040a124 

什麼是指針的值是什麼意思?

根據Wikipedia

的指針在內存引用位置