struct的变量,可以调用reciver为this和*this的方法,都可以。
比如
func (p *Person) method() string {
return "执行method方法"
}
func main() {
p1 := Person{"Jack"}
p1.str()
p2 := &Person{"Jack"}
p2.str()
}
当p1为变量时,可以调用指针方法,p2为指针时,同样可以。
然而!
type obj interface {
method() string
}
type Person struct {
name string
}
func (p *Person) method() string {
fmt.Println("执行string方法")
return "ok"
}
func main() {
var obj obj
obj = &Person{"Jack"}
fmt.Println(obj)
}
当Person实现obj接口时,把Person初始化给接口类型obj时,
若实现方法为指针拷贝方法,则必须给obj赋值&Person,obj必须为指针,否则报错。
若实现方法为副本拷贝方法,则给obj赋值Person,&Person都可以。
这是为什么呢?
个人理解,当结构体method实现接口method时,相当于在方法签名种添加了reciver,而结构体实现接口,必须要保证方法签名一致,也就是说,obj必须和(p *Person) 中的形式相同。
接口特征汇总程序:
//接口
/*
interface:
特征:
1、接口的实现
2、接口的组合、嵌套
3、空接口任意类型
4、接口断言
坑:
当接口包含指针receiver方法时,必须使用指针赋值给接口。
无法只用值拷贝给接口。
*/
package main
import (
"fmt"
"os"
)
type method interface {
method(string)
}
type ptmethod interface {
ptmethod(string)
}
//obj嵌套组合了method接口和ptmethod接口(类比java继承)
type obj interface {
method
ptmethod
}
//接口的实现,即一个类型实现了一个接口类型所有的方法,即为实现接口,无需显示声明
type person struct {
name string
}
func (p person) method(str string) {
fmt.Println(str)
}
func (p *person) ptmethod(str string) {
fmt.Println(str)
}
//自定义控制台格式化输出,形参为变长空接口
func myPrint(a ...interface{}) (n int, err error) {
return fmt.Fprintln(os.Stdout, a...)
}
func main() {
var p1 person = person{"Jack"}
var p2 *person = &person{"Tom"}
//自身,可以调用 自身方法 & 指针方法
p1.method("自身调用自身方法")
p1.ptmethod("自身调用指针方法") //此处应该是golang底层给默认了*p1
//指针,可以调用 自身方法 & 指针方法
p2.method("指针调用自身方法")
p2.ptmethod("指针调用指针方法")
var intf1,intf2 obj
//坑 intf1 = p1 如果直接把p1赋值给接口类型,报错:
/*
报错信息:cannot use p1 (type person) as type obj in assignment:
person does not implement obj (ptmethod method has pointer receiver)
也就是说person没有实现obj,而是*person实现了obj
结论:当接口包含指针receiver方法时,必须使用指针赋值给接口
*/
intf1 = &p1
intf2 = p2
fmt.Println(intf1,intf2)
intf1.method("指针接口调用继承而来的method方法")
//任意类型
var v1 interface {} = person{"Ada"}
myPrint(v1)
v1 = 1
myPrint(v1)
v1 = "hello"
myPrint(v1)
v1 = map[string]string{"傻子":"小明"}
myPrint(v1)
//断言
if v, bool := v1.(map[string]string) ;bool{
myPrint(v)
}else {
//type 需要和 switch 配套使用
switch v1.(type){
case int:
fmt.Println("v1 为 int")
default:
fmt.Println("v1 是什么?who cares")
}
}
}