1

下面的代码打开一个 .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)
}
4

2 回答 2

7

因为映射结构本身不包含值,而是指向保存值的结构。

文档中所述

像切片一样,映射包含对底层数据结构的引用。如果您将地图传递给更改地图内容的函数,则更改将在调用者中可见。

这就像你传递一个指向函数的指针:它让函数改变你的值。

这是相同现象的另一个示例:

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
}
于 2013-09-09T12:47:07.810 回答
2

该函数不是修改变量,而是修改绑定到变量的值。这是可能的,因为 amap是一个可变数据结构,将其传递给函数不会复制该结构。(Amap是对哈希表的隐式引用,并且该引用被传递。)

于 2013-09-09T12:47:05.503 回答