2013-09-09 3 views
1

Приведенный ниже код открывает TXT-файл и подсчитывает частоты слов. Я следую за книгу, и я запуталась:Переменная модификация в golang [Mutability]

Мой вопрос здесь:

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) 
} 

ответ

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 
} 
+0

... и реализация стоимости карты является простым старым указателем на непрозрачную структуру времени выполнения. – zzzz

+0

Для всех практических целей вы делаете «call-by-reference» вместо обычного «call-by-value». Вы передаете значение, но значение по существу представляет собой структуру данных на основе указателей, базовая структура данных будет ссылаться на обе переменные. –

2

Функция не изменяет переменную , но значение связано с переменной. Это возможно, потому что map - это изменяемая структура данных и передача ее функции не копирует структуру. (А map это неявно ссылка в хэш-таблицу, а ссылка передается вокруг.)