Golang中的方法
Golang并非是面向对象的语言,但是它可以模拟面向对象。Golang中的struct就类似于面向对象语言中的类,那么既然有了类,就要有对应的类的方法。Golang中以接收器(reciever)的形式实现struct的方法。
1.方法的声明
方法声明的形式如下
1 2 3 4
| type mytype struct {}
func (m mytype) method(para) return_type {} func (m *mytype) method(para) return_type {}
|
这就表示方法method是绑定在mytype上的,就类似于面向对象语言中类的成员方法
下面是一个实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| type Point struct { X, Y float64 }
func Distance(p, q Point) float64 { return math.Hypot(q.X-p.X, q.Y-p.Y) }
func (p Point) Distance(q Point) float64 { return math.Hypot(q.X-p.X, q.Y-p.Y) }
func main() { p := Point{1, 2} q := Point{4, 6}
fmt.Println(Distance(p, q)) fmt.Println(p.Distance(q)) }
|
- 以上例子中,虽然声明了两个同名的Distance函数,但是不会报错。因为第一个是属于当前包的包级别函数,第二个是属于Point类的方法。
- Go语言中,不同类型可以有相同的方法名,只要定义方法时用接收器区分开就可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| type myslice []int
func (s myslice) sum() int { sum := 0 for _, v := range s { sum += v } return sum }
func main() { s := myslice{1, 2, 3} fmt.Println(s.sum()) }
|
- Go语言中,与面向对象语言不同的是它不仅仅可以为struct定义方法,也可以为type定义的类型别名、slice、map、channel、func类型定义方法。但内置简单数据类型(int、float等)不行,interface类型不行。
- 上述不可以为简单类型定义方法,可以通过使用type a int这种形式为简单类型定义方法。
- 面向对象语言中,类的方法要定义在类的内部,Go语言中struct可以与方法的定义分开在不同的文件中,但一定要在一个包内。
- 方法就是函数,所以Go语言中没有重载的概念,同一类型中所有方法名都必须唯一
2.方法和函数的区别
本质上方法就是函数,方法是绑定了类型的特殊函数,需要指定类型的实例才可以调用。
3.值类型和指针类型的接受者
如果接收者是一个指针类型,那么同实例化类型一样会自动解除引用
1 2 3 4 5 6 7 8 9 10 11 12
| type Person struct {name, age int}
p := Person{} p1 := new(Person)
p.name = "xxs" p1.name = "sdad"
func (a *mytype1) add() ret_type {} a.add()
|
方法的接受者有两种类型:值类型和指针类型。它们在使用上有很大的区别
1 2
| func (p person) setname(name string) { p.name = name } func (p *person) setage(age int) { p.age = age }
|
- 对于setname方法,它的reciever是值类型的,那么在接收参数时是拷贝完整的Person的数据结构,无论实例是值类型还是指针类型,方法内部使用和修改的都是实例的副本,不会影响外部原始副本的值。
- 对于setage方法,它的reciever是指针类型的,那么在接收参数时是拷贝指针,无论实例是值类型还是指针类型,方法内部使用和修改的都是原始实例的数据。
如下例所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| type Person struct { name string age int }
func (p *Person) getname() string { return p.name }
func (p *Person) getage() int { return p.age }
func (p Person) setname(name string) { p.name = name }
func (p *Person) setage(age int) { p.age = age }
func main() { p1 := Person{} p1.setname("nyx") p1.setage(10) fmt.Println(p1.getname()) fmt.Println(p1.getage())
p2 := new(Person) p2.setname("nyx") p2.setage(10) fmt.Println(p2.getname()) fmt.Println(p2.getage()) }
|
4.嵌套struct中的方法
与属性类似,内部struct的方法也会被嵌套,外部struct可以直接调用内部struct的方法。如果外部struct有方法与内部strcut方法同名,那么直接调用的话就是调用外部strcut的方法,想要调用内部struct的对应方法需要使用间接调用的方式
Go语言的struct支持嵌套多个匿名字段,也就是说一个struct可以有多个内部struct,相当于支持多重继承
5.重写String()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type Person struct { name string age int }
func (p *Person) String() string { return p.name + ": " + strconv.Itoa(p.age) }
func mian() { p := new(Person) p.name = "nyx" p.age = 24 fmt.Println(p) }
|