Go 支持指针,允许在程序中通过引用传递值或者数据结构。
package mainimport "fmt"// 我们将通过两个函数:`zeroval` 和 `zeroptr` 来比较指针和// 值类型的不同。`zeroval` 有一个 `int` 型参数,所以使用值// 传递。`zeroval` 将从调用它的那个函数中得到一个 `ival`// 形参的拷贝。func zeroval(ival int) { ival = 0}// `zeroptr` 有一和上面不同的 `*int` 参数,意味着它用了一// 个 `int`指针。函数体内的 `*iptr` 接着_解引用_ 这个指针,// 从它内存地址得到这个地址对应的当前值。对一个解引用的指// 针赋值将会改变这个指针引用的真实地址的值。func zeroptr(iptr *int) { *iptr = 0}func main() { i := 1 fmt.Println("initial:", i) zeroval(i) fmt.Println("zeroval:", i) // 通过 `&i` 语法来取得 `i` 的内存地址,例如一个变量 // `i` 的指针。 zeroptr(&i) fmt.Println("zeroptr:", i) // 指针也是可以被打印的。 fmt.Println("pointer:", &i)}
# `zeroval` 在 `main` 函数中不能改变 `i` 的值,但是# `zeroptr` 可以,因为它有一个这个变量的内存地址的# 引用。$ go run pointers.goinitial: 1zeroval: 1zeroptr: 0pointer: 0x42131100
Go 的结构体 是各个字段字段的类型的集合。这在组织数据时非常有用。
// Go 的_结构体_ 是各个字段字段的类型的集合。// 这在组织数据时非常有用。package mainimport "fmt"// 这里的 `person` 结构体包含了 `name` 和 `age` 两个字段。type person struct { name string age int}func main() { // 使用这个语法创建了一个新的结构体元素。 fmt.Println(person{"Bob", 20}) // 你可以在初始化一个结构体元素时指定字段名字。 fmt.Println(person{name: "Alice", age: 30}) // 省略的字段将被初始化为零值。 fmt.Println(person{name: "Fred"}) // `&` 前缀生成一个结构体指针。 fmt.Println(&person{name: "Ann", age: 40}) // 使用点来访问结构体字段。 s := person{name: "Sean", age: 50} fmt.Println(s.name) // 也可以对结构体指针使用`.` - 指针会被自动解引用。 sp := &s fmt.Println(sp.age) // 结构体是可变的。 sp.age = 51 fmt.Println(sp.age)}
$ go run structs.go{Bob 20}{Alice 30}{Fred 0}&{Ann 40}Sean5051
Go 支持在结构体类型中定义方法 。
// Go 支持在结构体类型中定义_方法_ 。package mainimport "fmt"type rect struct { width, height int}// 这里的 `area` 方法有一个_接收器类型_ `rect`。func (r *rect) area() int { return r.width * r.height}// 可以为值类型或者指针类型的接收器定义方法。这里是一个// 值类型接收器的例子。func (r rect) perim() int { return 2*r.width + 2*r.height}func main() { r := rect{width: 10, height: 5} // 这里我们调用上面为结构体定义的两个方法。 fmt.Println("area: ", r.area()) fmt.Println("perim:", r.perim()) // Go 自动处理方法调用时的值和指针之间的转化。你可以使 // 用指针来调用方法来避免在方法调用时产生一个拷贝,或者 // 让方法能够改变接受的数据。 rp := &r fmt.Println("area: ", rp.area()) fmt.Println("perim:", rp.perim())}
$ go run methods.go area: 50perim: 30area: 50perim: 30# 接下来我们将 Go 语言中组织和命名相关的方法集合的机# 制:接口。
接口 是方法特征的命名集合。
// _接口_ 是方法特征的命名集合。package mainimport "fmt"import "math"// 这里是一个几何体的基本接口。type geometry interface { area() float64 perim() float64}// 在我们的例子中,我们将让 `square` 和 `circle` 实现// 这个接口type square struct { width, height float64}type circle struct { radius float64}// 要在 Go 中实现一个接口,我们只需要实现接口中的所有// 方法。这里我们让 `square` 实现了 `geometry` 接口。func (s square) area() float64 { return s.width * s.height}func (s square) perim() float64 { return 2*s.width + 2*s.height}// `circle` 的实现。func (c circle) area() float64 { return math.Pi * c.radius * c.radius}func (c circle) perim() float64 { return 2 * math.Pi * c.radius}// 如果一个变量的是接口类型,那么我们可以调用这个被命名的// 接口中的方法。这里有一个一通用的 `measure` 函数,利用这个// 特性,它可以用在任何 `geometry` 上。func measure(g geometry) { fmt.Println(g) fmt.Println(g.area()) fmt.Println(g.perim())}func main() { s := square{width: 3, height: 4} c := circle{radius: 5} // 结构体类型 `circle` 和 `square` 都实现了 `geometry` // 接口,所以我们可以使用它们的实例作为 `measure` 的参数。 measure(s) measure(c)}
$ go run interfaces.go{3 4}1214{5}78.5398163397448331.41592653589793# 要学习更多关于 Go 的接口的知识,看看这篇# [很棒的博文](http://jordanorelli.tumblr.com/post/32665860244/how-to-use-interfaces-in-go)。
联系客服