<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 4.10\. Rotting cats 在我們上面創建的file包(package)基礎之上,實現一個簡單的Unix工具 "cat(1)", "progs/cat.go": ``` 05 package main 07 import ( 08 "./file" 09 "flag" 10 "fmt" 11 "os" 12 ) 14 func cat(f *file.File) { 15 const NBUF = 512 16 var buf [NBUF]byte 17 for { 18 switch nr, er := f.Read(buf[:]); true { 19 case nr < 0: 20 fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String()) 21 os.Exit(1) 22 case nr == 0: // EOF 23 return 24 case nr > 0: 25 if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { 26 fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String()) 27 } 28 } 29 } 30 } 32 func main() { 33 flag.Parse() // Scans the arg list and sets up flags 34 if flag.NArg() == 0 { 35 cat(file.Stdin) 36 } 37 for i := 0; i < flag.NArg(); i++ { 38 f, err := file.Open(flag.Arg(i), 0, 0) 39 if f == nil { 40 fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err) 41 os.Exit(1) 42 } 43 cat(f) 44 f.Close() 45 } 46 } ``` 現在應該很容易被理解,但是還有些新的語法"switch". 比如: 包括了"for"循環, "if"和 "switch"初始化的語句。在"switch"語句的18行用了"f.Read()"函數的返回值"nr"和"er"做為 變量(25行中的"if"也采用同樣的方法)。這里的"switch"語法和其他語言語法基本相同,每個分支(cases) 從上到下查找是否與相關的表達式相同,分支(case)的表達式不僅僅是常量(constants)或整數(integers), 它可以是你想到的任意類型。 這個"switch"的值永遠是"真(true)", 我們會一直執行它, 就像"for"語句,不寫值默認是"真"(true). 事實上,"switch"是從"if-else"由來的。在這里我們要說明, "switch"語句中的每個"分支"(case)都 默認隱藏了"break". 在25行中調用"Write()"采用了slicing來取得buffer數據. 在標準的GO中提供了Slices對I/O buffers的操作。 現在讓我們做一個"cat"的升級版讓"rot13"來處理輸入, 就是個簡單的字符處理,但是要 采用GO的新特性"接口(interface)"來實現。 這個"cat()"使用了2個子程序"f":"Read()"和"String", 讓我們定義這2個接口, 源碼參考 "progs/cat_rot13.go" ``` 26 type reader interface { 27 Read(b []byte) (ret int, err os.Error) 28 String() string 29 } ``` 任何類型的方法都有 reader 這兩個方法 —— 也就是說實現了這兩個方法, 任何類型的方法都能使用。由于 file.File 實現了 reader 接口,我們就可以讓 cat 的子程序訪問 reader 從而取代了 *file.File 并且能正常工作,讓我們來些第二個類型實現 reader , 一個關注現有的 reader ,另一個 rot13 只關注數據。我們只是定義了這個類型和 實現了這個方法并沒有做其他的內部處理, 我們實現了第二個 reader 接口. ``` 31 type rotate13 struct { 32 source reader 33 } 35 func newRotate13(source reader) *rotate13 { 36 return &rotate13{source} 37 } 39 func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) { 40 r, e := r13.source.Read(b) 41 for i := 0; i < r; i++ { 42 b[i] = rot13(b[i]) 43 } 44 return r, e 45 } 47 func (r13 *rotate13) String() string { 48 return r13.source.String() 49 } 50 // end of rotate13 implementation ``` (42行的"rot13"函數非常簡單,沒有必要在這里進行討論) 為了使用新的特性,我們定義了一個標記(flag): ``` 14 var rot13Flag = flag.Bool("rot13", false, "rot13 the input") ``` 用它基本上不需要修改"cat()"這個函數: ``` 52 func cat(r reader) { 53 const NBUF = 512 54 var buf [NBUF]byte 56 if *rot13Flag { 57 r = newRotate13(r) 58 } 59 for { 60 switch nr, er := r.Read(buf[:]); { 61 case nr < 0: 62 fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String()) 63 os.Exit(1) 64 case nr == 0: // EOF 65 return 66 case nr > 0: 67 nw, ew := file.Stdout.Write(buf[0:nr]) 68 if nw != nr { 69 fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String()) 70 } 71 } 72 } 73 } ``` (我們應該對 main 和 cat 單獨做些封裝,不僅僅是對類型參數的修改,就當是練習)從56行到 58行: 如果 rot13 標記是真,封裝的 reader 就會接受數據并傳給 rotate13 并處理. 注意: 這個接口的值是變量,不是指針,這個參數是 reader 類型,不是 *reader , 盡管后面轉換為 指向結構體的指針。 這里是執行結果: ``` % echo abcdefghijklmnopqrstuvwxyz | ./cat abcdefghijklmnopqrstuvwxyz % echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13 nopqrstuvwxyzabcdefghijklm % ``` 也許你會說使用注入依賴(dependency injection)能輕松的讓接口以一個文件描述符執行。 接口(interfaces)是Go的一個特性,一個接口是由類型實現的,接口就是聲明該類型的所有方法。 也就是說一個類型可以實現多個不同的接口, 沒有任何類型的限制,就像我們的例子"rot13". "file.File"這個類型實現了"reader", 它也能實現"writer", 或通過其他的方法來實現這個接口。 參考空接口(empty interface) ``` type Empty interface {} ``` 任何類型都默認實現了空接口,我們可以用空接口來保存任意類型。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看