2017-05-20 10 views
0

그래서 나는 내 머리를 감쌀 수없는 초급 질문으로 돌아 왔습니다. 다음 코드를 실험하고있었습니다.Golang : 포인터, 할당 및 예기치 않은 동작을 이해하는 데 도움이됩니다.

func main() { 
start := time.Now() 
var powers []*big.Int 
for i := 1; i < 1000; i++ { 
    I := big.NewInt(int64(i)) 
    I.Mul(I, I) 
    powers = append(powers, I) 
} 
fmt.Println(powers) 
fmt.Println(time.Since(start)) 
start = time.Now() 
var seqDiffs []*big.Int 
diff := new(big.Int) 
for i, v := range powers { 
    if i == len(powers)-2 { 
     break 
    } 
    diff = v.Sub(powers[i+1], v) 
    seqDiffs = append(seqDiffs, diff) 
} 
fmt.Println(seqDiffs) 
fmt.Println(time.Since(start)) 
} 

내 의도는

diff.Sub(powers[i+1], v) 

그러나이 이상에 걸쳐 반복 년과 1995 년 (올바른 마지막 값) 인 seqDiffs의 값에서 결과 다음과 같은 방법으로 diff를 위해 서브()의 결과를 할당하는 것이 었습니다. 나는 seqDiffs가 동일한 메모리 주소에 대한 포인터 단지 목록입니다하지만 내가 이해 해달라고 무엇 때문에이 가능성이 알고 왜이 모든 홀수 번호의 목록 인 seqDiffs 결과

v.Sub(powers[i+1], v) 
seqDiffs = append(seqDiffs, v) 

잘 다음 작품 3에서 1995까지 정확한지는 모르겠지만 이것은 본질적으로 여전히 동일한 메모리 주소에 대한 포인터 목록입니다. 또한 seqDiffs가 동일한 메모리 주소에 대한 포인터의 목록이기도 한 경우에도 다음과 같이 올바른 이유는 무엇입니까?

diff = v.Sub(powers[i+1], v) 
seqDiffs = append(seqDiffs, diff) 

또한 내가 그것을 다음과 같은 방법

diff := new(*big.Int) 
for i, v := range powers { 
if i == len(powers)-2 { 
    break 
} 
diff.Sub(powers[i+1], v) 
seqDiffs = append(seqDiffs, diff) 
} 

을하려고 노력하지만, IDE에서 이러한 오류를받은 :

*./sequentialPowers.go:26: calling method Sub with receiver diff (type **big.Int) requires explicit dereference 
./sequentialPowers.go:27: cannot use diff (type **big.Int) as type *big.Int in append* 

가 어떻게이 "명시 적"역 참조 할 것?

+0

에 추가, 당신은 결국 한 포인터를 가리키는 포인터. new()는 무언가를 가리키는 포인터를 반환하고 새로운 포인터는 큰 포인터를 가리 킵니다. 그래서'diff : = new (* big.Int)'는 diff를 포인터에 대한 포인터로 만듭니다. 이것은 큰 포인터를 기대하기 때문에 그것을 사용하려는 곳에서는 사용할 수 없다는 것을 의미합니다. –

답변

2

Go의 포인터와 관련된 문제를 디버깅 할 때 fmt.Printf을 사용하여 %p을 사용하여 관심있는 변수의 메모리 주소를 인쇄하십시오.

왜 모든 인덱스가 동일한 값을하는 슬라이스에 *big.Int 결과의 당신의 조각에 diff.Sub(powers[i+1], v)의 결과를 추가 할 때에 관해서는 당신의 첫 번째 질문에 관해서

- 메모리 주소 diff의 값을 업데이트하는 것은에 할당하고 해당 포인터의 복사본을 슬라이스에 추가합니다. 따라서 슬라이스의 모든 값은 동일한 값에 대한 포인터입니다.

diff의 메모리 주소를 인쇄하면이 경우가 표시됩니다. 당신의 조각 채우기 후 - 다음과 같은 일을 뭔가 : 두 번째 예에서

for _, val := range seqDiffs { 
    fmt.Printf("%p\n", val) // when i ran this - it printed 0xc4200b7d40 every iteration 
} 

을의 값 v는 다른 주소에서 big.Int에 대한 포인터입니다. v.Sub(..)의 결과를 diff에 지정하면 diff가 가리키는 기본 주소가 업데이트됩니다. 따라서 슬라이스에 diff을 추가하면 고유 한 주소에 포인터 사본이 추가됩니다. fmt.Printf를 사용하면 당신과 같이이 볼 수 있습니다 -

var seqDiffs []*big.Int 
diff := new(big.Int) 
for i, v := range powers { 
    if i == len(powers)-2 { 
     break 
    } 
    diff = v.Sub(powers[i+1], v) 
    fmt.Printf("%p\n", diff) // 1st iteration 0xc4200109e0, 2nd 0xc420010a00, 3rd 0xc420010a20, etc 
    seqDiffs = append(seqDiffs, diff) 
} 

을 두 번째 질문에 대해서는 - 이동은 지정된 유형의 메모리를 할당하지만 (check the docs)를 초기화하지 않는 경우에 new 키워드를 사용. 귀하의 경우 new에 대한 호출은 big.Int (**big.Int)에 대한 포인터에 포인터 유형을 할당하므로 append 호출에서이 유형을 사용할 수 없다는 컴파일러 오류가 발생합니다.

명시 적으로 다음에 코드를 수정해야 할 것, 그것에 Sub를 호출하기 위해 diff 역 참조하려면 : 이동에

(*diff).Sub(powers[i+1], v) 

, 셀렉터 표현은 당신을 위해 구조체에 대한 포인터를 역 참조 만에 이 경우 포인터에 대한 포인터를 호출하기 때문에 을 명시 적으로 참조 해제해야합니다. 이동의 구조체 (선택 식) 메소드를 호출에

매우 유익한 읽기를 찾을 수

here 그리고 마지막 질문에 대해 슬라이스

seqDiffs = append(seqDiffs, *diff) 
+0

응답 해 주셔서 감사합니다. 그것은 매우 도움이됩니다. 수학/큰 패키지를 사용할 때마다 문제가 발생합니다. 결과적으로 예상되는 결과를 얻지 만 필자는 느낌을 남기고, 코딩을 바라 보는 코드가 생길 때까지 타입 오류가 발생하여 많은 시간을 소비하게 될 것입니다. 고유 한 메모리 주소가있는 변수를 생성하는 이러한 방법을 지속적으로 사용할 수있는 허용 된 간단한 방법이 있습니까? –

+0

루프 내에서 diff, diff : = new (big.Int)의 초기화를 이동하면 diff.Sub (powers [i + 1], v)와 함께 아름답게 작동합니다. 이것이 모든 반복에 대해 고유 한 메모리 주소에 변수 diff를 생성하기 때문에 이것이라고 가정합니다. –

+0

@StephenAdams - 도움이되기 때문에 기쁘다 - 문제를 풀 때 diff를 움직이는 것이 좋은 해결책이다. – syllabix