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)
点击这里查看我们当前的代码。