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 に答える