golang中的变量修改[Mutability]

时间:2013-09-09 12:45:02

标签: go

以下代码打开.txt文件并计算单词频率。我正在读一本书,我感到困惑:

我的问题在这里:

filename := os.Args[1]
frequencyForWord := map[string]int{}
updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)

我创建了一个名为frequencyForWord的变量,并将其传递给一个不返回任何名为func updateFrequencies的函数

此函数修改变量,这就是为什么当我fmt.Println(frequencyForWord)时,它会向我显示一个地图,其中包含单词作为键及其计数值。

我的问题是:

为什么我不必做这样的事情

frequencyForWord = updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
// And then change func updateFrequencies to something to returns a map

我想是为了让一个函数修改一个我需要传入变量的变量作为这样的引用updateFrequencies(filename, &frequencyForWord)

原始代码:

package main

import(
"fmt"
"path/filepath"
"os"
"log"
"bufio"
"strings"
"unicode"
)

func main() {
  if len(os.Args) == 1 || os.Args[1] == "-h" {
    fmt.Printf("usage: %s <file>\n", filepath.Base(os.Args[0]))
    os.Exit(1)
  }
  filename := os.Args[1]
  frequencyForWord := map[string]int{}
  updateFrequencies(filename, frequencyForWord)
  fmt.Println(frequencyForWord)
}



func updateFrequencies(filename string, frequencyForWord map[string]int) string {
  file, err := os.Open(filename)
  if err != nil {
    log.Printf("Failed to open the file: %s.", filename)
  }
  defer file.Close()
  readAndUpdateFrequencies(bufio.NewScanner(file), frequencyForWord)
}

func readAndUpdateFrequencies(scanner *bufio.Scanner, frequencyForWord map[string]int) {
  for scanner.Scan() {
    for _, word := range SplitOnNonLetter(strings.TrimSpace(scanner.Text())) {
      frequencyForWord[strings.ToLower(word)] += 1
    }
  }

  if err := scanner.Err(); err != nil {
    log.Fatal(err)
  }
}

func SplitOnNonLetter(line string) []string {
  nonLetter := func(char rune) bool { return !unicode.IsLetter(char) }
  return strings.FieldsFunc(line, nonLetter)
}

2 个答案:

答案 0 :(得分:7)

因为地图结构本身并不包含值,而是指向包含值的结构。

正如the documentation所述:

  

与切片类似,贴图保存对基础数据结构的引用。如果   您将地图传递给更改地图内容的函数   更改将在调用者中可见。

就像你将一个指针传递给一个函数一样:它让函数改变你的价值。

这是同一现象的另一个例子:

type A struct {
    b *B
}
type B struct {
    c int
} 
func incr(a A) {
    a.b.c++
}
func main() {
    a := A{}
    a.b = new(B)
    fmt.Println(a.b.c) // prints 0
    incr(a)
    fmt.Println(a.b.c) // prints 1
}

答案 1 :(得分:2)

该函数不修改变量,但绑定到变量。这是可能的,因为map是一个可变数据结构并将其传递给函数不会复制结构。 (map隐含地是哈希表的引用,并且传递引用。)