2017-05-20 47 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) 

但是這會導致重複一遍又一遍seqDiffs的值是1995年(正確的最後一個值)來比較差異。我知道,因爲seqDiffs只是一個相同的內存地址指針的列表,但我不明白這很可能就是爲什麼下面的作品就好了

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

這導致seqDiffs是所有的奇數號碼的列表從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()返回一個指向某個東西的指針,並且在new中你已經把它指向了一個big.Int。所以'diff:= new(* big.Int)'使diff成爲指針的指針。這意味着它不能用於你想要使用它的地方,因爲它只需要一個指向big.Int的指針。 –

回答

2

當用Go中的指針調試問題時,一種理解正在發生什麼的方法是使用fmt.Printf使用%p來打印感興趣變量的內存地址。

在問候你的第一個問題,爲什麼追加的diff.Sub(powers[i+1], v)的結果,你的*big.Int導致切片,每一個指數的值相同切片時 - 要更新的內存地址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) 
} 

關於你提到的第二個問題 - 使用new關鍵字在Go分配指定類型的內存,但不將其初始化(check the docs)。在你的情況下調用new爲指向big.Int**big.Int)的指針分配一個指針類型,因此編譯器錯誤說你不能在調用append時使用這種類型。

要明確取消引用爲了調用就可以了Sub,你將不得不修改代碼以下列diff

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

在Go中,選擇表達,解除引用指針結構爲你,但在這種情況下,你正在調用一個指針指向一個指針的方法,因此你必須明確地解引用它。

一個上呼籲在圍棋結構(選擇表達式)方法非常翔實的讀取,可以發現here

並把它添加到切片

seqDiffs = append(seqDiffs, *diff) 
+0

感謝您的回覆;這是非常有幫助的。每次使用數學/大型軟件包時,我都會遇到問題。這會導致在很多分鐘內打印出類型錯誤,直到我終於有了能夠產生預期輸出的代碼,但讓我感覺到了,並且我的編碼看起來像是我繞過該塊三次到達角落。是否有一種可以接受的簡單方法來一致地使用這些方法,這些方法將導致具有唯一內存地址的變量? –

+0

在循環內部移動diff,diff:= new(big.Int)的初始化,使用diff.Sub(powers [i + 1],v)精美地運行。我認爲這是因爲這會在每次迭代的獨特內存地址處創建一個變量差異? –

+0

@StephenAdams - 很高興爲您提供幫助 - 在循環內移動diff可以很好地解決您的問題 – syllabix