go遞歸函數如何傳遞數組切片slice


數組切片slice這個東西看起來很美好,真正用起來會發現有諸多的不爽。

第一,數組、數組切片混淆不清,使用方式完全一樣,有時候一些特性又完全不一樣,搞不清原理很容易誤使用。

第二,數組切片的append操作,每次對slice append操作,都返回一個新的slice的引用,對slice的引用沒法保持,這樣在函數傳遞slice的情況下append,在調用函數的上下文中看不到slice append的效果。如果想要這種方式湊效,不得不另辟蹊徑。本文主要說一下如何解決這個窘境的方法。

函數傳遞slice存在什么問題?

func sliceModify(slice []int) {
    // slice[0] = 88
    slice = append(slice, 6)
}
func main() {
    slice := []int{1, 2, 3, 4, 5}
    sliceModify(slice)
    fmt.Println(slice)
}

輸出:

[1 2 3 4 5]

問題所在:

雖然說數組切片在函數傳遞時是按照引用的語義傳遞的,比如說在sliceModify函數里面slice[0] = 88,在方法調用的上下文中,調用函數對slice引用的改表是看得見的。

但是在對slice進行append操作的時候,我們驚奇的發現,這次又不管用了。原因就是append操作會返回這個擴展了的slice的引用,必須讓原引用重新賦值為新slice的引用,說白了就是,傳遞過來的這個指針原來指了內存中的A區域,A區域是原數組的真正所在。經過一次 append之后,要把這個指針改為指向B,B對應append后新的slice的引用。但是方法調用的上下文里的slice指針還是指向了老的A內存區域。

這個邏輯實在有些奇葩,這里我不得不再次吐槽append的設計。有人說這個問題好解決啊,只需要在sliceModify函數的返回值中把append后新的slice引用返回就好了。這樣做當然是可以滴,但是像遞歸調用的函數就不好解決了。

下面就說一下這個問題的解決辦法,方法也很簡單,就是傳遞指針的指針。雖然有些繞,但是總算把問題解決了。當然也有其他的辦法,比如按照java等語言的方式,自己實現一個ArrayList,在對可變數組擴展的時候,千萬表改變引用了。

func sliceModify(slice *[]int) {
    *slice = append(*slice, 6)
}
func main() {
    slice := []int{1, 2, 3, 4, 5}
    sliceModify(&slice)
    fmt.Println(slice)
}

這次就可以輸出預期的結果了:

[1 2 3 4 5 6]

遞歸調用的例子:

 

func insertTo10(arr *[]int) {
    length := len(*arr)
    if length == 10 {
        return
    }
    *arr = append(*arr, length)
    insertTo10(arr)
}
func main() {
    arr10 := []int{}
    insertTo10(&arr10)
    fmt.Println(arr10)
}

 

還可以訪問我樹莓派上搭的博客地址:

http://www.codeforfun.info/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM