2013-05-05 20 views
14

Şu anda egzersizleri biriyle sorun haline Git Lang öğretici üzerinde çalışıyor, ama ran ediyorum:Go'da Statik Başlatma?

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

egzersiz beni ROT13 şifre uygulamak gelmiştir. Bir bayttan döndürülmüş değere bir harita kullanarak şifreyi uygulamaya karar verdim, ancak bu haritayı başlatmanın en iyi yolundan emin değilim. Bir literal kullanarak haritayı başlatmak istemiyorum, ancak bir alfabeyle ve döngü içindeki ayar (anahtar, değer) çiftleriyle döngü yaparak programlı olarak yapmayı tercih ediyorum. Ayrıca haritanın sadece Rot13Reader struct/object'ten erişilebilir olmasını ve tüm örneklerin (?) Aynı haritayı paylaştığını (aynı zamanda her bir Rot13Reader için bir kopya yerine) olmasını isterim.

İşte benim şimdiki çalışma Git program:

İşte
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) 
} 

sorunlar Bununla var şunlardır: Ben main()

  • ı don içinde rot13Map hazırlamak zorunda kalmak istemiyoruz

    • Küresel kapsamda olmak rot13Map istiyorum.
    • Ben rot13Reader her kopyası olmasını istemiyoruz ayrı rot13Map

    Ben git istediğini elde etmek için bir yol var mı?

  • +0

    {...} 'değil func init (...) {...} '? (ikincisi bir derleyici hatasına neden olur) – jlhawn

    +0

    Init, ana gibi parametrelere izin vermez sanırım. – zk82

    +0

    http://golang.org/ref/spec, bir init işlevinin (paket düzeyinde func init()) bir programdaki her yerden gönderilemeyeceğini belirtir. – zk82

    cevap

    11

    Bunu yapmak için rot13 paketi yaparım. Haritayı init() işlevinde programlı olarak oluşturabilir ve tüm rot13 kod çözücülerinize global olarak bir paket düzeyi olarak sağlayabilirsiniz. Init işlevi, paketiniz içe aktarıldığında çalışır.

    Rot13Reader, paketteki tek tür olduğundan, haritanıza erişebilen tek kişi budur.

    UYARI: Test edilen tüm kodlar.

    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 
    } 
    

    Açıkçası, turda başka bir paket yapamazsınız. Ana tarafından erişilebilir rot13Map ile sıkışmış. İstediğiniz ayrımı elde etmek için Git'i yerel olarak çalıştırmanız gerekir.

    4

    Kodunuzu basitleştirir ve init işlevini kullanırım. Örneğin,

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

    Çıkış: Bütünlük adına

    You cracked the code! 
    
    6

    : başlatma çalışması için bir paket içinde init fonksiyonunun yanı sıra sadece bir kez verilen fonksiyonunu çalıştırır sync.Once vardır.

    Bir “Once” nesnesi oluşturursunuz ve fonksiyonunuzda Do ile görüşün. Once nesnesinin durumu değişmediği sürece, sağlanan işlev yalnızca bir kez çağrılır.

    Örnek:

    import "sync" 
    
    var readerInitOnce sync.Once 
    
    func (rotr *rot13Reader) Read(p []byte) (int, error) { 
        readerInitOnce.Do(initRot13Map) 
        ... 
    } 
    
    Biraz ilgili notu, neden var init = fonksiyon (...) `olarak main`` benim iç içe işlev tanımlamak gerekiyor On