## 7.3\. 數據結構
我們先定義一個結構類型,用于保存數據。wiki系統由一組互聯的wiki頁面組成,每個wiki頁面包含內容和標題。我們定義wiki頁面為結構page, 如下:
```
type page struct {
title string
body []byte
}
```
類型[]byte表示一個byte slice。(參考Effective Go了解slices的更多信息) 成員body之所以定義為[]byte而不是string類型,是因為[]byte可以直接使用io包的功能。
結構體page描述了一個頁面在內存中的存儲方式。但是,如果要將數據保存到磁盤的話,還需要給page類型增加save方法:
```
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
```
類型方法的簽名可以這樣解讀:“save為page類型的方法,方法的調用者為page類型的指針變量p。該成員函數沒有參數,返回值為os.Error,表示錯誤信息。”
該方法會將page結構的body部分保存到文本文件中。為了簡單,我們用title作為文本文件的名字。
方法save的返回值類型為os.Error,對應WriteFile(標準庫函數,將byte slice寫到文件中)的返回值。通過返回os.Error值,可以判斷發生錯誤的類型。如果沒有錯誤,那么返回nil(指針、接口和其他一些類型的零值)。
WriteFile的第三個參數為八進制的0600,表示僅當前用戶擁有新創建文件的讀寫權限。(參考Unix手冊 open(2) )
下面的函數加載一個頁面:
```
func loadPage(title string) *page {
filename := title + ".txt"
body, _ := ioutil.ReadFile(filename)
return &page{title: title, body: body}
}
```
函數loadPage根據頁面標題從對應文件讀取頁面的內容,并且構造一個新的 page變量——對應一個頁面。
go中函數(以及成員方法)可以返回多個值。標準庫中的io.ReadFile在返回[]byte的同時還返回os.Error類型的錯誤信息。前面的代碼中我們用下劃線“_”丟棄了錯誤信息。
但是ReadFile可能會發生錯誤,例如請求的文件不存在。因此,我們給函數的返回值增加一個錯誤信息。
```
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
```
現在調用者可以檢測第二個返回值,如果為nil就表示成功裝載頁面。否則,調用者可以得到一個os.Error對象。(關于錯誤的更多信息可以參考os package documentation)
現在,我們有了一個簡單的數據結構,可以保存到文件中,或者從文件加載。我們創建一個main函數,測試相關功能。
```
func main() {
p1 := &page{title: "TestPage", body: []byte("This is a sample page.")}
p1.save()
p2, _ := loadPage("TestPage")
fmt.Println(string(p2.body))
}
```
編譯后運行以上程序的話,會創建一個TestPage.txt文件,用于保存p1對應的頁面內容。然后,從文件讀取頁面內容到p2,并且將p2的值打印到 屏幕。
可以用類似以下命令編譯運行程序:
```
$ 8g wiki.go
$ 8l wiki.8
$ ./8.out
This is a sample page.
```
(命令8g和8l對應GOARCH=386。如果是amd64系統,可以用6g和6l)
點擊這里查看我們當前的代碼。
- 1. 關于本文
- 2. Go語言簡介
- 3. 安裝go環境
- 3.1. 簡介
- 3.2. 安裝C語言工具
- 3.3. 安裝Mercurial
- 3.4. 獲取代碼
- 3.5. 安裝Go
- 3.6. 編寫程序
- 3.7. 進一步學習
- 3.8. 更新go到新版本
- 3.9. 社區資源
- 3.10. 環境變量
- 4. Go語言入門
- 4.1. 簡介
- 4.2. Hello,世界
- 4.3. 分號(Semicolons)
- 4.4. 編譯
- 4.5. Echo
- 4.6. 類型簡介
- 4.7. 申請內存
- 4.8. 常量
- 4.9. I/O包
- 4.10. Rotting cats
- 4.11. Sorting
- 4.12. 打印輸出
- 4.13. 生成素數
- 4.14. Multiplexing
- 5. Effective Go
- 5.1. 簡介
- 5.2. 格式化
- 5.3. 注釋
- 5.4. 命名
- 5.5. 分號
- 5.6. 控制流
- 5.7. 函數
- 5.8. 數據
- 5.9. 初始化
- 5.10. 方法
- 5.11. 接口和其他類型
- 5.12. 內置
- 5.13. 并發
- 5.14. 錯誤處理
- 5.15. Web服務器
- 6. 如何編寫Go程序
- 6.1. 簡介
- 6.2. 社區資源
- 6.3. 新建一個包
- 6.4. 測試
- 6.5. 一個帶測試的演示包
- 7. Codelab: 編寫Web程序
- 7.1. 簡介
- 7.2. 開始
- 7.3. 數據結構
- 7.4. 使用http包
- 7.5. 基于http提供wiki頁面
- 7.6. 編輯頁面
- 7.7. template包
- 7.8. 處理不存在的頁面
- 7.9. 儲存頁面
- 7.10. 錯誤處理
- 7.11. 模板緩存
- 7.12. 驗證
- 7.13. 函數文本和閉包
- 7.14. 試試!
- 7.15. 其他任務
- 8. 針對C++程序員指南
- 8.1. 概念差異
- 8.2. 語法
- 8.3. 常量
- 8.4. Slices(切片)
- 8.5. 構造值對象
- 8.6. Interfaces(接口)
- 8.7. Goroutines
- 8.8. Channels(管道)
- 9. 內存模型
- 9.1. 簡介
- 9.2. Happens Before
- 9.3. 同步(Synchronization)
- 9.4. 錯誤的同步方式
- 10. 附錄
- 10.1. 命令行工具
- 10.2. 視頻和講座
- 10.3. Release History
- 10.4. Go Roadmap
- 10.5. 相關資源