Golang 遞歸訪問目錄與函數修改數組的問題

我想寫一個這樣的函數:
訪問一個目錄下的所有*.db文件。并放入filepath[]中。filepath是一個結構體:

type filepath struct {
    fullpath string   //文件路徑名
    filename string //文件名
}

寫完了的程序是這個樣子的,打印時:

package main

import (
    "io/ioutil"
    "strings"
    "path"
)

const rootpath string = "D://testfile/2345"

type filepath struct {
    fullpath string
    filename string
}

func main() {
    var files []filepath
    files = make([]filepath, 0, 1)
    //dir,_:=ioutil.ReadDir(rootpath)
    //遞了個歸
    readdir(rootpath, files)
    for _, v := range files {
        println(v.filename, v.fullpath)
    }
}

func readdir(dirs string, files []filepath) {

    dir, _ := ioutil.ReadDir(dirs)
    for _, v := range dir {
        if v.IsDir() {
            dir2 := path.Join(dirs, v.Name())
            readdir(dir2, files)
        } else {
            if strings.HasSuffix(v.Name(), ".db") {
                var str string = v.Name()
                files = append(files, filepath{fullpath: path.Join(dirs, str), filename: str})
            }
        }
    }
}
//輸出:

(什么~~都沒有 一臉懵b.jpg)```
像我這種JB型boy(腳本型語言boy)不常用指針就會有這種錯誤。加點信息調試下?

//把最后一個else 里加兩句,變成下面的:
else {
if strings.HasSuffix(v.Name(), ".db") {
str := v.Name()
println("老地址", files)
files = append(files, filepath{fullpath: path.Join(dirs, str), filename: str})
println("新地址", files)
//println(len(files) )
}
//輸出如下(一對一對看還是很方便 []里的數字含義為 [len/cap]):
老地址 [0/1]0xc042033f58
新地址 [1/1]0xc042033f58
老地址 [1/1]0xc042033f58
新地址 [2/2]0xc042054b00
老地址 [2/2]0xc042054b00
新地址 [3/4]0xc042066b00
老地址 [3/4]0xc042066b00
新地址 [4/4]0xc042066b00
老地址 [4/4]0xc042066b00
新地址 [5/8]0xc042036300
老地址 [5/8]0xc042036300
新地址 [6/8]0xc042036300
老地址 [6/8]0xc042036300
新地址 [7/8]0xc042036300
老地址 [7/8]0xc042036300
新地址 [8/8]0xc042036300


分析下,按照append的尿性,每次內存不夠就添加 len的空間,會不會生成一段時的內存,重新分配給指針???
**先確認下會不會分配吧!!!!**
一共是八個append
1. 只有一個空間,正好 
1. 空間不夠了,加 len   現在2個了
1. 空間又不夠了 ,加len 現在4個了
1. 夠 
1. 不夠 加len 8個
1. 夠
1. 夠 
1. 夠

內存指針變了3次,那么,就可以肯定,一開始的files = make([]filepath, 0, 1) 應該有第一組數據啊~
再打印下內存,println換下位置

func main() {
var files []filepath
files = make([]filepath, 0, 1)
//dir,_:=ioutil.ReadDir(rootpath)
//遞了個歸
println("老地址", files)
readdir(rootpath, files)
for _, v := range files {
println(v.filename, v.fullpath)
}
}

func readdir(dirs string, files []filepath) {
println("新地址", files)
dir, _ := ioutil.ReadDir(dirs)
for _, v := range dir {
if v.IsDir() {
dir2 := path.Join(dirs, v.Name())
readdir(dir2, files)
} else {
if strings.HasSuffix(v.Name(), ".db") {
str := v.Name()
files = append(files, filepath{fullpath: path.Join(dirs, str), filename: str})
//println(len(files) )
}
}
}
}
//打印信息如下:
老地址 [0/1]0xc042033f58
新地址 [0/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58
新地址 [1/1]0xc042033f58

我發現,頭指針依舊是那個頭指針,所以結論:
** 隨著append增加,頭指針依舊是那個頭指針**
那么問題來了,為什么就是打印不出來!!!
難道,append有坑,加的東西沒有給上?
寫個小程序試試吧。

package main

func main() {
var p1 []int=[]int{1,2,3,4,5}
change(p1)
println(p1[5])
}
func change(p1 []int) {
p1=append(p1,2222)
}
//輸出
panic :數組越界

此時,我真的是。。。。
我突然想到了什么東西!!!!
** 突然明白過來,p1是個切片, main中的p1始終指向 {1,2,3,4,5} 而不會指向{1,2,3,4,5,2222 }**
程序修改如下:

package main

func main() {
var p1 []int=[]int{1,2,3,4,5}
change2(&p1)
println(p1[5])
}
func change2(p1 *[]int) {
p1=append(p1,2222)
}
//輸出: 2222

到這里,我又有了一想到了前面近乎完美的調試信息,就是這一段:
> 分析下,按照append的尿性,每次內存不夠就添加 len的空間,會不會生成一段時的內存,重新分配給指針???
**先確認下會不會分配吧!!!!**
一共是八個append
1. 只有一個空間,正好 
1. 空間不夠了,加 len   現在2個了
1. 空間又不夠了 ,加len 現在4個了
1. 夠 
1. 不夠 加len 8個
1. 夠
1. 夠 
1. 夠

我猜,99.9%的可能是   `一個文件夾中有8個.db文件`  我去看了一下,還真是。
我想到了兩種解決方案:
1. 像上面的函數那樣改指針(去TMD)
2. 返回一個新的切片

最后我選2,別人看起來也方便點,于是,整個程序就變成:

package main

import (
"io/ioutil"
"strings"
"path"
)

const rootpath string = "D://testfile/2345"

type filepath struct {
fullpath string
filename string
}

func main() {
var files []filepath
files = make([]filepath, 0, 1)
files= readdir(rootpath, files)
for _, v := range files {
println(v.filename, v.fullpath)
}
}

func readdir(dirs string, files []filepath) []filepath {
dir, _ := ioutil.ReadDir(dirs)
for _, v := range dir {
if v.IsDir() {
dir2 := path.Join(dirs, v.Name())
files=readdir(dir2, files)
} else {
if strings.HasSuffix(v.Name(), ".db") {
str := v.Name()
files = append(files, filepath{fullpath: path.Join(dirs, str), filename: str})
//println(len(files) )
}
}
}
return files
}

再說一下go 的 path吧,感覺功能有點少,并沒有 go.getpath這個功能,只能自己手動記錄文件路徑。
唉,程序算是寫完了吧,如果我上面寫得有什么問題,希望大家指正。






最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容