英文:
Variable modification in golang [Mutability]
问题
以下是翻译好的内容:
下面的代码打开一个.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)
// 然后将func updateFrequencies更改为返回一个映射
我认为为了让函数修改一个变量,我需要将变量作为引用传递,像这样updateFrequencies(filename, &frequencyForWord)
。
原始代码:
package main
import (
"bufio"
"fmt"
"log"
"os"
"path/filepath"
"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)
}
英文:
The below code opens up a .txt file and counts the word frequencies. I am following a book and I got confused:
My question is here:
filename := os.Args[1]
frequencyForWord := map[string]int{}
updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
I create a variable called frequencyForWord
and pass it into a function that does not return anything called func updateFrequencies
This function modifies the variable and that's why when I do fmt.Println(frequencyForWord)
it shows me a map that has words as keys and their counts as values.
My question is:
why don't I have to do something like this
frequencyForWord = updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
// And then change func updateFrequencies to something to returns a map
I thought in order for a function to modify a variable I need to pass in the variable as a reference like this updateFrequencies(filename, &frequencyForWord)
Original Code:
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)
}
答案1
得分: 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) // 输出 0
incr(a)
fmt.Println(a.b.c) // 输出 1
}
英文:
Because the map structure doesn't contain the values itself but points to the structures holding the values.
As written in the documentation :
> Like slices, maps hold references to an underlying data structure. If
> you pass a map to a function that changes the contents of the map, the
> changes will be visible in the caller.
That's just like when you pass a pointer to a function : it lets the function change your value.
Here's another example of the same phenomenon :
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
}
答案2
得分: 2
该函数并不修改变量,而是修改绑定到该变量的值。这是因为map
是一个可变的数据结构,并且将其传递给函数时并不会复制该结构。(map
隐式地是对哈希表的引用,并且该引用被传递到各处。)
英文:
The function is not modifying the variable, but the value bound to the variable. That's possible because a map
is a mutable data structure and passing it to a function does not copy the structure. (A map
is implicitly a reference to a hash table and the reference is passed around.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论