试着掌握Go的指针

时间:2017-03-04 09:41:08

标签: pointers go

我已经编写了一个小片段,以递归方式遍历目录并根据扩展名返回一片文件([]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")
}

主要问题是使用*aggregatoraggregator *[]string),&[]string{}*extsexts *[]string)。我来自javascript世界,其中每个对象基本上都是一个指针,你只能显式复制对象和数组。另一方面,似乎如果我没有使用指针(*aggregator等),这些对象将在每次函数迭代时被复制。

我是采用这种方法还是错过了什么?

2 个答案:

答案 0 :(得分:2)

虽然这个可视化并不是特别关于Go(它是关于Java)但它是一个完美的实现可视化指针和值的使用(1): enter image description here

如您所见,指针实际上不包含任何数据,但指向数据所在的位置。因此,通过指针对该数据进行的任何修改实际上都是在数据本身上执行的。但是数据不一定存在于我们的指针使用的位置。

我们可能需要指针时会有不同的情况。例如,当您想要在一个特定位置修改实际值(而不是传递这些值)或者当您的数据太大以至于成本太高而无法发送实际内容时。您可以使用/ 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博客文章。