2013-05-05 18 views
14

Im Moment arbeite ich auf dem Tutorial Go Lang, sondern lief in Problem mit einem der Übungen:Statische Initialisierung in Go?

https://tour.golang.org/methods/23

Die Übung mir eine ROT13 Chiffre umzusetzen hat. Ich beschloss, die Chiffre mit einer Karte von einem Byte zu seinem gedrehten Wert zu implementieren, aber ich bin mir nicht sicher, wie diese Karte am besten initialisiert werden kann. Ich möchte die Map nicht mit einem Literal initialisieren, sondern würde es lieber programmatisch machen, indem ich ein Alphabet durchbohre und Paare (Schlüssel, Wert) innerhalb der Schleife setze. Ich möchte auch, dass die Map nur von Rot13Reader struct/object aus zugänglich ist und dass alle Instanzen (?) Dieselbe Map teilen (statt einer Kopie pro Rot13Reader).

Hier ist meine aktuelle Arbeits Go Programm:

package main 

import (
    "io" 
    "os" 
    "strings" 
) 

type rot13Reader struct { 
    r io.Reader 
} 

var rot13Map = map[byte]byte{} 

func (rotr *rot13Reader) Read(p []byte) (int, error) { 
    n, err := rotr.r.Read(p) 
    for i := 0; i < n; i++ { 
     if sub := rot13Map[p[i]]; sub != byte(0) { 
      p[i] = sub 
     } 
    } 
    return n, err 
} 

func main() { 
    func() { 
     var uppers = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
     var lowers = []byte("abcdefghijklmnopqrstuvwxyz") 

     var init = func (alphabet []byte) { 
      for i, char := range alphabet { 
       rot13_i := (i + 13) % 26 
       rot13Map[char] = alphabet[rot13_i] 
      } 
     } 

     init(uppers) 
     init(lowers) 
    }() 

    s := strings.NewReader("Lbh penpxrq gur pbqr!") 
    r := rot13Reader{s} 
    io.Copy(os.Stdout, &r) 
} 

Hier sind die Probleme, die ich mit diesem haben:

  • Ich will nicht rot13Map vorzubereiten haben in main()
  • I don möchte nicht rot13Map in globalen Geltungsbereich sein.
  • Ich möchte nicht jede Kopie eines rot13Reader ein separates in Go rot13Map

Gibt es eine Möglichkeit zu erreichen, was ich will haben?

+0

Auf einer etwas verwandten beachten Sie, warum muss ich meine verschachtelte Funktion in 'main' als' var init = func (...) {...} 'und nicht definieren 'func init (...) {...}'? (Letzteres verursacht einen Compiler-Fehler) – jlhawn

+0

Ich denke, die Init erlaubt keine Parameter, wie Main. – zk82

+0

http://golang.org/ref/spec gibt an, dass auf eine init-Funktion (func init() auf Paketebene) nicht von überall in einem Programm zugegriffen werden kann. – zk82

Antwort

11

Um dies zu tun, würde ich ein rot13-Paket machen. Sie können die Map in einer init() -Funktion programmatisch erstellen und sie allen RotID-Decodern als globale Paketebene zur Verfügung stellen. Die init-Funktion wird ausgeführt, wenn das Paket importiert wird.

Da Rot13Reader der einzige Typ im Paket ist, ist es der einzige, der auf Ihre Karte zugreifen kann.

WARNUNG: Alle Codes wurden nicht getestet.

package rot13 

import (
    "io" 
) 

var rot13Map = map[byte]byte{} 

func init() { 
    var uppers = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    var lowers = []byte("abcdefghijklmnopqrstuvwxyz") 

    var init = func(alphabet []byte) { 
     for i, char := range alphabet { 
      rot13_i := (i + 13) % 26 
      rot13Map[char] = alphabet[rot13_i] 
     } 
    } 

    init(uppers) 
    init(lowers) 
} 

type Reader struct { 
    r io.Reader 
} 

func (rotr Reader) Read(p []byte) (int, error) { 
    n, err := rotr.r.Read(p) 
    for i := 0; i < n; i++ { 
     if sub := rot13Map[p[i]]; sub != byte(0) { 
      p[i] = sub 
     } 
    } 
    return n, err 
} 

Offensichtlich können Sie nicht ein anderes Paket in der Go-Tour machen. Sie sind fest mit rot13Map von Main zugegriffen werden. Sie müssen Go lokal ausführen, um die gewünschte Trennung zu erhalten.

4

Ich würde Ihren Code vereinfachen und eine init Funktion verwenden. Zum Beispiel

package main 

import (
    "io" 
    "os" 
    "strings" 
) 

type rot13Reader struct { 
    r io.Reader 
} 

func newRot13Map() map[byte]byte { 
    n := byte('Z' - 'A' + 1) 
    rot13 := make(map[byte]byte, 2*n) 
    for ltr := byte(0); ltr < n; ltr++ { 
     sub := (ltr + 13) % n 
     rot13[ltr+'A'] = sub + 'A' 
     rot13[ltr+'a'] = sub + 'a' 
    } 
    return rot13 
} 

var rot13Map map[byte]byte 

func init() { 
    rot13Map = newRot13Map() 
} 

func (rotr *rot13Reader) Read(p []byte) (int, error) { 
    n, err := rotr.r.Read(p) 
    for i, ltr := range p[:n] { 
     if sub, ok := rot13Map[ltr]; ok { 
      p[i] = sub 
     } 
    } 
    return n, err 
} 

func main() { 
    s := strings.NewReader("Lbh penpxrq gur pbqr!") 
    r := rot13Reader{s} 
    io.Copy(os.Stdout, &r) 
} 

Ausgang:

You cracked the code! 
6

Aus Gründen der Vollständigkeit: Für Initialisierungsarbeit neben der init Funktion in einem Paket gibt es sync.Once, das nur einmal eine bereitgestellte Funktion ausgeführt wird.

Sie erstellen ein Once-Objekt und rufen Do mit Ihrer Funktion darauf. Solange der Zustand des Objekts Once nicht geändert wird, wird die angegebene Funktion nur einmal aufgerufen.

Beispiel:

import "sync" 

var readerInitOnce sync.Once 

func (rotr *rot13Reader) Read(p []byte) (int, error) { 
    readerInitOnce.Do(initRot13Map) 
    ... 
} 
Verwandte Themen