我已经编写了一个小片段,以递归方式遍历目录并根据扩展名返回一片文件([]string
)。它似乎有效,但我无法完全理解指针背后的想法以及如何正确使用它。
package main
import (
"path/filepath"
"io/ioutil"
"fmt"
)
// aggregator slice should hold the result (a slice of filepaths)
// dir is the current directory being listed
// exts is a slice of extensions that should be included in the result
func recurse(aggregator *[]string, dir string, exts *[]string) []string {
files, _ := ioutil.ReadDir(dir)
for _, file := range files {
// current filepath
path := filepath.Join(dir, file.Name())
// if directory, recursively analyze it
if file.IsDir() {
*aggregator = recurse(aggregator, path, exts)
// else check if file is of proper extension and add it to aggregator
} else {
for _, ext := range *exts {
if (filepath.Ext(path) == ext) {
*aggregator = append(*aggregator, path)
break
}
}
}
}
return *aggregator
}
func getTemplates(templatesDir string, templatesExtensions ...string) {
templates := recurse(&[]string{}, templatesDir, &templatesExtensions)
// for testing purposes just print filepaths
for _, t := range templates {
fmt.Printf("%s\n", t)
}
}
func main() {
getTemplates("./templates", ".tmpl", ".html")
}
主要问题是使用*aggregator
(aggregator *[]string
),&[]string{}
和*exts
(exts *[]string
)。我来自javascript
世界,其中每个对象基本上都是一个指针,你只能显式复制对象和数组。另一方面,似乎如果我没有使用指针(*aggregator
等),这些对象将在每次函数迭代时被复制。
我是采用这种方法还是错过了什么?
答案 0 :(得分:2)
虽然这个可视化并不是特别关于Go(它是关于Java)但它是一个完美的实现可视化指针和值的使用(1):
如您所见,指针实际上不包含任何数据,但指向数据所在的位置。因此,通过指针对该数据进行的任何修改实际上都是在数据本身上执行的。但是数据不一定存在于我们的指针使用的位置。
我们可能需要指针时会有不同的情况。例如,当您想要在一个特定位置修改实际值(而不是传递这些值)或者当您的数据太大以至于成本太高而无法发送实际内容时。您可以使用/ some指针指向这个大数据,并且每个人(例如每个函数)都有一个指向该数据的指针,可以读取或修改它。正如我们所说,我们可以根据需要提供相同数据的指针。因此,可能有许多指针只是相同的,一个数据。这些指针的值是相同的;这是源数据(对象)的地址。
忘记在Go中添加切片会被指针/引用传递,但是你无法修改切片(添加/删除项目)。你可以修改它的项目。如果需要修改切片本身,则必须使用指向切片的指针。否则,如果您只是将其作为某些值的容器传递,则无需担心,因为它们不会每次都被复制。
(1)Source
答案 1 :(得分:0)
在go切片中有引用类型,以及地图和指针(我很确定字符串太过于不要在我身上问:)但请参阅here进行讨论。 。因此,这些特定类型会自动通过引用传递。因此,实际变量本身的计算结果为指针,其中值将是参考地址。
因此,在您的情况下,将aggregator *[]string
更改为aggregator []string
可能更安全,而且您的数据将不仅复制传递的引用。当然,除了此更改之外,您还需要更改之前解除引用aggregator
的所有代码,例如
// Change this line
*aggregator = append(*aggregator, path)
// To this
aggregator = append(aggregator, path)
这样做的原因可能源于基于C语言,其中数组只是指向已分配内存开始的指针。
注意:包括结构在内的所有其他类型都不遵循此模式(接口是另一个有趣的异常read)。此代码看起来似乎可以通过filepath.Walk()
大大简化。
如需更多信息,请参阅this博客文章。