简介
在Go-Structure对struct做了简单的介绍,本文参考如下书目继续丰富本专题。
- 《Web Development with Go》 Chapter 3
- 《The Go Programming Language》4.4 Page99
pointer and nonpointer method receiver
在Go-Structure一文给出的示例代码中,使用的都是pointer receiver。事实上,也可以使用nonpointer receiver。事实上,也可以使用nonpointer
示例:
package main
import (
"fmt"
)
type Point struct {
x, y int
}
func (p Point) GetX() int {
return p.x
}
func (p Point) GetY() int {
return p.y
}
func (p *Point) SetX(ix int) {
(*p).x = ix
}
func (p *Point) SetY(iy int) {
(*p).y = iy
}
func (p *Point) SetY2(iy int) {
p.y = iy
}
func (p Point) SetY3(iy int) {
p.y = iy
}
func test1() {
p := Point{1, 2}
fmt.Print(p, "\t")
fmt.Print("x=", p.GetX(), "\t")
fmt.Print("y=", p.GetY(), "\t")
p.SetX(3)
p.SetY(4)
fmt.Print(p, "\t")
(&p).SetX(5)
(&p).SetY(6)
fmt.Print(p, "\t")
fmt.Println()
}
// SetY() -> SetY2()
func test2() {
p := Point{1, 2}
fmt.Print(p, "\t")
fmt.Print("x=", p.GetX(), "\t")
fmt.Print("y=", p.GetY(), "\t")
p.SetX(3)
p.SetY2(4)
fmt.Print(p, "\t")
(&p).SetX(5)
(&p).SetY2(6)
fmt.Print(p, "\t")
fmt.Println()
}
// SetY() -> SetY3()
func test3() {
p := Point{1, 2}
fmt.Print(p, "\t")
fmt.Print("x=", p.GetX(), "\t")
fmt.Print("y=", p.GetY(), "\t")
p.SetX(3)
p.SetY3(4)
fmt.Print(p, "\t")
(&p).SetX(5)
(&p).SetY3(6)
fmt.Print(p, "\t")
fmt.Println()
}
func test4() {
p := &Point{1, 2}
fmt.Print(p, "\t")
fmt.Print("x=", p.GetX(), "\t")
fmt.Print("y=", p.GetY(), "\t")
p.SetX(3)
p.SetY(4)
fmt.Print(p, "\t")
//calling method SetX with receiver &p (type **Point) requires explicit dereference
//(&p).SetX(5)
//(&p).SetY(6)
//fmt.Print(p, "\t")
fmt.Println()
}
/*
D:\examples>go run helloworld.go
test1: {1 2} x=1 y=2 {3 4} {5 6}
test2: {1 2} x=1 y=2 {3 4} {5 6}
test3: {1 2} x=1 y=2 {3 2} {5 2}
test4: &{1 2} x=1 y=2 &{3 4}
D:\examples>
*/
func main() {
fmt.Print("test1: ")
test1()
fmt.Print("test2: ")
test2()
fmt.Print("test3: ")
test3()
fmt.Print("test4: ")
test4()
}
要点
copied from:《Web Development with Go》 Chapter 3, Page 39
If you want to modify the data of a receiver from the method, the receiver must be a pointer
If the struct has a pointer receiver on some its methods, it is better to use it for the rest of the methods because it enables better consistency and predictability for the struct behaviors.
pointer & dot notation
这里再介绍指针类型和.操作符的特殊意义。在前面的例子中,有如下代码:
func (p *Point) SetY2(iy int) {
p.y = iy
}
其等价于:
func (p *Point) SetY2(iy int) {
(*p).y = iy
}
这种语法是Go中非常特殊的一点。这种语法的证据源于《The Go Programming Language》4.4 Page 100,代码如下:
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
The dot notation also works with a pointer to a struct:
var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"
The last statement is equivalent to
(*employeeOfTheMonth).Position += " (proactive team player)"
Go指针的这种语法可以简化代码。
结构自嵌套
一个结构S内部不能有S成员,但可以有指向S的成员(指针 *S).
type tree struct {
value int
left, right *tree
}
比较结构体对象
Go中不能重载==操作符,对于要比较(同一种)结构体的两个对象,则要求其每个field都是可以比较的。而且在比较的时候,是按照每个field依次比较。也可以自定义比较的函数,比如Equals()。
package main
import (
"fmt"
)
type Point struct {
x, y int
}
func (p Point) GetX() int {
return p.x
}
func (p Point) GetY() int {
return p.y
}
func (p *Point) SetX(ix int) {
p.x = ix
}
func (p *Point) SetY(iy int) {
p.y = iy
}
func (p *Point) Equals(point Point) bool {
return p.x == point.x
}
func Equals(p1 Point, p2 Point) bool {
return p1.x == p2.x
}
func main() {
p1 := Point{1, 2}
p2 := Point{x:1, y:2}
p3 := Point{1, 3}
fmt.Println(p1 == p2, p2 == p3) // true, false
fmt.Println(p1.x == p2.x && p1.y == p2.y) // true. Equals to "p1 == p2"
fmt.Println(p1.Equals(p3)) // true
fmt.Println(Equals(p2, p3)) // true
}
有疑问加站长微信联系(非本文作者)