Go 객체의 포인터 값을 어떻게 인쇄합니까? 포인터 값은 무엇을 의미합니까?


83

나는 단지 Go를 가지고 놀면서 구조가 값이나 참조로 전달되는시기에 대한 좋은 멘탈 모델을 아직 가지고 있지 않습니다.

이것은 매우 멍청한 질문 일 수 있지만 조금 실험하고 여전히 동일한 개체에서 작업하고 있는지 또는 복사본을 만들 었는지 확인하고 싶습니다 (값으로 전달).

객체의 포인터 (또는 포인터 값이 gc에 의해 변경된 경우 내부 ID)를 인쇄하는 방법이 있습니까?

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를 볼 수있는 방법이 있습니까?

답변:


114

Go 함수 인수는 값으로 전달됩니다.

먼저, 예제에서 관련없는 부분을 버려서 단순히 인수를 값으로 전달하고 있음을 쉽게 알 수 있습니다. 예를 들면

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

함수에서 main, iint메모리 위치 변수 ( &i) 0xf800000040의 초기 값은 ( i) 42.

함수에서 main, p포인터이다 int메모리 위치 (AT 변수 &p) 0xf8000000f0의 값 (이 함께 p= &i) 0xf800000040내지 An되는 점 int값 ( *p= i) 42.

함수에서 main, byval(p)값 (할당하는 함수 호출 p= &i) 0xf800000040메모리 위치 (에서의 인수 &p) 0xf8000000f0함수에 byval파라미터 q메모리 위치 ( &q) 0xf8000000d8. 즉, byval매개 변수에 메모리가 할당 q되고 main byval인수 값 p이 할당됩니다. p및 의 값 q은 처음에는 동일하지만 변수 pq는 다릅니다.

함수 byval포인터 사용 q( *int포인터의 사본 임), p( *int), 정수 *q( i) INT 새로운 값으로 설정된다 4143. 돌아 오기 전에 마지막에. 포인터 qnil(0 값)으로 설정되어 복사본 p이므로 영향을주지 않습니다 q.

함수에서 main, p포인터이다 int메모리 위치 (AT 변수 &p) 0xf8000000f0의 값 (이 함께 p= &i) 0xf800000040새로운 어떤 점 int값 ( *p= i) 4143.

함수에서 main, iint메모리 위치 변수 ( &i) 0xf800000040의 최종 값은 ( i) 4143.

귀하의 예 에서 함수 호출에 대한 인수로 사용되는 함수 main변수 는 함수 매개 변수 와 동일하지 않습니다 . 이름은 같지만 범위와 메모리 위치가 다른 변수입니다. 함수 매개 변수 는 함수 호출 인수를 숨 깁니다 . 이것이 제 예에서 인수와 매개 변수 변수의 이름을 지정 하고sgotestgotestssspq 각각의 차이를 강조 할 수 있습니다.

사용자의 예에서, ( &s) 0x4930d4변수에 대한 메모리 위치의 주소 s함수의 main함수 호출의 인수로서 사용 gotest(s, done)하고, 0x4974d8기능을위한 메모리 위치의 주소 gotest파라미터 s. s = nil함수의 끝에서 매개 변수를 설정하면 gotest변수 s에 영향을주지 않습니다 main. sin mainsin gotest은 별개의 메모리 위치입니다. 유형 측면에서 &sis **Something, sis *Something, *sis Something입니다. &s(메모리 위치 주소) s에 대한 포인터이며, 유형의 익명 변수 (메모리 위치 주소)에 대한 포인터입니다.Something. 값의 측면에서, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s,와 main.s.number == gotest.s.number.

mkb의 현명한 조언을 받아들이고 println(&s). fmt예를 들어 패키지를 사용하십시오.

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

포인터는 동일한 메모리 위치를 가리킬 때 동일한 값을 갖습니다. 포인터는 다른 메모리 위치를 가리킬 때 다른 값을 갖습니다.


내 예에서 gotest는 'Something'에 대한 포인터를 사용하므로 동일한 객체를 참조한다고 가정하고 go-routine 내부의 값을 변경 한 후 객체의 값도 주 함수에서 변경 되었기 때문입니다. . 인쇄 된 포인터 값이 다릅니다.
Jeroen Dirks

@JamesDean 귀하의 예제에서는 포인터 값 & s 유형 ** Something을 인쇄하고 있으며 이는 포인터 값 s 유형 * Something과 동일하지 않습니다. 값으로 포인터를 전달하도록 예제를 수정했습니다.
peterSO

@ 제임스 딘 당신은 포인터의 주소 (받는 사람 즉, 포인터 인쇄 s, 포인터) - 포인터는 값에 의해 전달의 주소는 s동일하지 않습니다 s. gotest 함수가 println( s )intead했다면 포인터 값을 인쇄합니다.
nos

오 이제 무슨 일이 일어나고 있는지 봅니다. println (& s)을 수행하여 포인터 값 대신 포인터 주소를 인쇄했습니다. 내가 println (s)을했다면 그것은 main과 go 루틴 함수에서 같은 포인터를 보여 주었을 것입니다.
Jeroen Dirks

@JamesDean 정확합니다. Go에서 s * Something의 경우 & s, s 및 * s의 차이를 아는 것이 중요합니다.
peterSO

6

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}

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

4
내장 된 println을 사용하지 말고 fmt 패키지에서 적절한 것을 사용하십시오 : golang.org/doc/go_spec.html#Bootstrapping
mkb

2

Go 객체의 포인터 값을 어떻게 인쇄 합니까?

package main

import (
    "fmt"
)

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

결과 :

0x1040a124

포인터 값은 무엇을 의미합니까?

Wikipedia 에 따르면 :

포인터는 메모리의 위치를 ​​참조합니다.


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

산출:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.