2013-05-05 23 views
14

私は現在、ゴーラングのチュートリアルに取り組んが、演習のいずれかに問題に遭遇したよ:運動は私がROT13暗号を実装していGoでの静的初期化?

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

。私はバイトからその回転値までのマップを使って暗号を実装することにしましたが、このマップを初期化する最良の方法は不明です。リテラルを使用してマップを初期化したくないのですが、アルファベットをループし、ループ内で(キー、値)のペアを設定することによってプログラムで行う方が好きです。また、Rot13Readerのstruct/objectからしかアクセスできないすべてのインスタンス(?)が(Rot13Readerごとに1つのコピーではなく)同じマップを共有するようにしたいと思います。

は、ここに私の現在の作業囲碁プログラムです:

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

の問題は、私がこれを持っている:私はmain()

  • Iドンでrot13Mapを準備する必要がありますする必要はありません

    • rot13Mapをグローバルスコープにします。
    • 私はrot13Readerの各コピーはしたくない別のrot13Map

    私は行くに欲しいものを達成するための方法はありますか?

  • +0

    ありません'func init(...){...}'? (後者はコンパイラエラーを引き起こします) – jlhawn

    +0

    initはmainのようなパラメータを許可していないと思います。 – zk82

    +0

    http://golang.org/ref/specは、プログラム内のどこからでもinit関数(パッケージレベルでのfunc init())を参照できないことを指定しています。 – zk82

    答えて

    11

    これを行うには、rot13パッケージを作成します。 init()関数でプログラムでマップを作成し、すべてのrot13デコーダにグローバルなパッケージレベルとして提供することができます。パッケージがインポートされると、init関数が実行されます。

    Rot13Readerはパッケージ内の唯一のタイプなので、マップにアクセスできるのは唯一のタイプです。

    警告:すべてのコードがテストされていません。

    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 
    } 
    

    もちろん、外出先で別のパッケージを作成することはできません。あなたはrot13Mapがメインでアクセスできるようになっています。 Goをローカルに実行して、必要な分離を行う必要があります。

    4

    コードを簡略化し、init機能を使用します。例えば、

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

    出力:完全を期すために

    You cracked the code! 
    
    6

    :初期化作業のために、パッケージ内のinit機能のほかには、一度だけ供給関数を実行sync.Once、そこにあります。

    Onceオブジェクトを作成し、その上に関数Doを呼び出します。 Once オブジェクトの状態が変更されていない限り、指定された関数は1回だけ呼び出されます。

    例:私は `VARのinit = funcを(...){...}` `としてmain`の私のネストされた関数を定義する必要がない理由やや関連ノートで、オン

    import "sync" 
    
    var readerInitOnce sync.Once 
    
    func (rotr *rot13Reader) Read(p []byte) (int, error) { 
        readerInitOnce.Do(initRot13Map) 
        ... 
    } 
    
    関連する問題