2013-05-05 4 views
14

나는 현재 연습 중 하나를 문제로 이동 랭 튜토리얼 작업 만 실행 해요 :Go에서 정적 초기화?

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

운동 내게는 ROT13 암호화를 구현했다. 회전 된 값에 대한 바이트 맵을 사용하여 암호를 구현하기로 결정했지만이지도를 초기화하는 가장 좋은 방법은 확실하지 않습니다. 리터럴을 사용하여지도를 초기화하고 싶지는 않지만 프로그래밍 방식으로 알파벳을 반복하고 루프 내에서 (키, 값) 쌍을 설정하여 선호합니다. 또한 Rot13Reader 구조체/객체에서만 액세스 할 수있는지도를 원하고 모든 인스턴스 (?)가 Rot13Reader 당 하나의 사본이 아닌 동일한 맵을 공유하도록합니다.

여기에 내 현재 작업 이동 프로그램입니다 :

여기
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()

  • 나는 돈에 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 개체의 상태가 변경되지 않는 한 제공된 기능은 한 번만 호출됩니다.

    예 :

    import "sync" 
    
    var readerInitOnce sync.Once 
    
    func (rotr *rot13Reader) Read(p []byte) (int, error) { 
        readerInitOnce.Do(initRot13Map) 
        ... 
    } 
    
    다소 관련 노트, 왜 var에 초기화 =의 FUNC (...)`로 main``내 중첩 된 함수를 정의해야 하는가에