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

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 4.9\. I/O包 接下來我們使用open/close/read/write等基本的系統調用實現一個用于文件IO的包。 讓我們從文件file.go開始: ``` 05 package file 07 import ( 08 "os" 09 "syscall" 10 ) 12 type File struct { 13 fd int // file descriptor number 14 name string // file name at Open time 15 } ``` 文件的第一行聲明當前代碼對應&mdash;"file"&mdash;包,然后導入os和syscall兩個包。 包os封裝了不同操作系統底層的實現,例如將文件抽象成相同的類型。我們將在系統接口基礎 上封裝一個基本的文件IO接口。 另外還有其他一些比較底層的syscall包,它提供一些底層的系統調用(system's calls)。 接下來是一個類型(type)定義:用"type"這個關鍵字來聲明一個類。在這個例子里數據結構(data structure) 名為"File"。為了讓這事變的有趣些,我們的File包含了一個這個文件的名字(name)用來描述這個文件。 因為結構體名字"File"的首字母是大寫,所以這個類型包(package)可以被外部訪問。在GO中訪問規則的處理 是非常簡單的:如果頂極類型名字首字母(包括:function, method, constant or variable, or of a structure field or method)是大寫,那么引用了這個包(package)的使用者就可以訪問到它。不然 名稱和被命名的東西將只能有package內部看到。這是一個要嚴格遵循的規則,因為這個訪問規則是由 編譯器(compiler)強制規范的。在GO中,一組公開可見的名稱是"exported"。 在這個File例子中,所有的字段(fields)都是小寫所以從包外部是不能訪問的,不過我們在下面將會一個 一個對外訪問的出口(exported) —— 一個以大寫字母開頭的方法。 首先是一個創建File結構體的函數: ``` 17 func newFile(fd int, name string) *File { 18 if fd < 0 { 19 return nil 20 } 21 return &File{fd, name} 22 } ``` 這將返回一個指向新File結構體的指針,結構體存有文件描述符和文件名。這段代碼使用了GO的復合變量(composite literal)的概念,和創建內建的maps和arrays類型變量一樣。要創建在堆(heap-allocated)中創建一個新的 對象,我們可以這樣寫: ``` n := new(File); n.fd = fd; n.name = name; return n ``` 如果結構比較簡單的話,我們可以直接在返回結構體變量地址的時候初始化成員字段,如前面例子的 21行代碼所示。 我們可以用前面的函數(newFile)構造一些File類型的變量,返回File: ``` 24 var ( 25 Stdin = newFile(0, "/dev/stdin") 26 Stdout = newFile(1, "/dev/stdout") 27 Stderr = newFile(2, "/dev/stderr") 28 ) ``` 這里的newFile是內部函數,真正包外部可以訪問的函數是Open: ``` 30 func Open(name string, mode int, perm uint32) (file *File, err os.Error) { 31 r, e := syscall.Open(name, mode, perm) 32 if e != 0 { 33 err = os.Errno(e) 34 } 35 return newFile(r, name), err 36 } ``` 在這幾行里出現了一些新的東西。首先,函數Open返回多個值(multi-value):一個File指針和一個error( 等一下會介紹errors)》我們用括號來表來聲明返回多個變量值(multi-value),語法上它看 起來像第二個參數列表。syscall.Open系統調用同樣也是返回多個值multi-value。接著我們能在31行 創建了r和e兩個變量用于保存syscall.Open的返回值。函數最終也是返回2個值,分別為File指針和一個error。 如果syscall.Open打開失敗,文件描述r將會是個負值,newFile將會返回nil。 關于錯誤:os包包含了一些常見的錯誤類型。在用戶自己的代碼中也盡量使用這些通用的錯誤。 在Open函數中,我們用os.Error函數將Unix的整數錯誤代碼轉換為go語言的錯誤類型。 現在我們可以創建Files,我們為它定義了一些常用的方法(methods)。要給一個類型定義一個方法(method), 需要在函數名前增加一個用于訪問當前類型的變量。這些是為*File類型創建的一些方法: ``` 38 func (file *File) Close() os.Error { 39 if file == nil { 40 return os.EINVAL 41 } 42 e := syscall.Close(file.fd) 43 file.fd = -1 // so it can't be closed again 44 if e != 0 { 45 return os.Errno(e) 46 } 47 return nil 48 } 50 func (file *File) Read(b []byte) (ret int, err os.Error) { 51 if file == nil { 52 return -1, os.EINVAL 53 } 54 r, e := syscall.Read(file.fd, b) 55 if e != 0 { 56 err = os.Errno(e) 57 } 58 return int(r), err 59 } 61 func (file *File) Write(b []byte) (ret int, err os.Error) { 62 if file == nil { 63 return -1, os.EINVAL 64 } 65 r, e := syscall.Write(file.fd, b) 66 if e != 0 { 67 err = os.Errno(e) 68 } 69 return int(r), err 70 } 72 func (file *File) String() string { 73 return file.name 74 } ``` 這些并沒有隱含的this指針(參考C++類),而且類型的方法(methods)也不是定義在struct內部——struct結構 只聲明數據成員(data members)。事實上,我們可以給任意數據類型定義方法,例如:整數(integer),數組(array) 等。后面我們會有一個給數組定義方法的例子。 String這個方法之所以會被調用是為了更好的打印信息,我們稍后會詳細說明。 方法(methods)使用os.EINVAL來表示(os.Error的版本)Unix錯誤代碼EINVAL。 在os包中針對標準的error變量定義各種錯誤常量。 現在我們可以使用我們自己創建的包(package)了: ``` 05 package main 07 import ( 08 "./file" 09 "fmt" 10 "os" 11 ) 13 func main() { 14 hello := []byte("hello, world\n") 15 file.Stdout.Write(hello) 16 file, err := file.Open("/does/not/exist", 0, 0) 17 if file == nil { 18 fmt.Printf("can't open file; err=%s\n", err.String()) 19 os.Exit(1) 20 } 21 } ``` 這個"./"在導入(import)"./file"時告訴編譯器(compiler)使用我們自己的package,而不是在 默認的package路徑中找。 最后,我們來執行這個程序: ``` $ 6g file.go # compile file package $ 6g helloworld3.go # compile main package $ 6l -o helloworld3 helloworld3.6 # link - no need to mention "file" $ helloworld3 hello, world can't open file; err=No such file or directory $ ```
                  <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>

                              哎呀哎呀视频在线观看