今日概述
最近几天没来写日志,有点懈怠,今天开始总结下go的方法知识点。
1. 方法和函数的区别
- 方法有一个接收者对象(定义时显示写出来)
- 对于方法而言,值/指针调用编译器会自动转换成接收者的类型可以混用;但是函数不行—关键点。
比如:
package main
import "fmt"
type Person struct {
name string
age int
}
// 值接收者
func (p Person) Hello() {
fmt.Println("Hello")
}
// 指针接收者
func (p *Person) Welcome() {
fmt.Println("welcome")
}
// 函数 这个时候只能输入 值
func FunHello(name string) {
fmt.Println(name)
}
func main() {
p := Person{"张数", 12}
// 值/指针都可以调用
p.Hello()
(&p).Hello()
p.Welcome()
(&p).Welcome()
name := "dmy"
FunHello(name)
//FunHello(&name) cannot use &name (value of type *string) as string value in argument to FunHello
}
2. 结构体匿名字段-结构体方法提升
在上述情况下,字段结构体的方法会提升到当前结构体可用。
package main
import "fmt"
type Human struct {
work string
}
func (h *Human) WorkInfo() {
fmt.Printf("work info: %v\n", h.work)
}
type Person struct {
name string
age int
Human // 等同于字段名也是 Human Human的方法会提升
}
func (p *Person) Name() {
fmt.Printf("My name: %v\n", p.name)
}
func main() {
p := Person{
name: "张三",
age: 12,
Human: Human{work: "cleaner"}, // 虽然混合这里要分开写
}
// 此时person同时有了Person和Human的方法
p.Name()
p.WorkInfo()
}
3. 表达式
我的简单理解是,它可以用于将方法暂时不执行,留着后续执行;
它有两种:
- 方法值(这种封装了方法对象在里面)
- 方法表达式值(这种没有封装对象,执行是需要传参进入)
package main
import "fmt"
type Person struct {
name string
age int
}
func (p *Person) Name() {
fmt.Printf("My name: %v\n", p.name)
}
func (p Person) Age() {
fmt.Printf("My age: %v\n", p.age)
}
func main() {
p := Person{
name: "张三",
age: 12,
}
// 方法值表达式
Val := p.Name
Val() // 内部封装了对象p
// 方法表达式
exp := Person.Age
exp(p) // 内部没有封装对象p所以要传
}
另外一点区别是,对于表达式,如果是指针接收者,则写的时候必须严格按照指针写。
举例说明:
package main
import "fmt"
type Person struct {
name string
age int
}
func (p *Person) Name() {
fmt.Printf("My name: %v\n", p.name)
}
func (p Person) Age() {
fmt.Printf("My age: %v\n", p.age)
}
func main() {
p := Person{
name: "张三",
age: 12,
}
// 方法表达式 - 此时写随便写都行
exp := Person.Age
exp(p) // 内部没有封装对象p所以要传
// 这里改成指针 也没问题
exp1 := (*Person).Age
exp1(&p)
// 如果是指针类型则只能指针
exp2 := (*Person).Name
exp2(&p)
// 报错
// exp3 := Person.Name
// exp3(p) // invalid method expression Person.Name (needs pointer receiver (*Person).Name)
}
4. 一点特别的说明
- nil可以转换成指针类型
- 但是nil 不能转换成值类型
package main
type Data struct{}
func (Data) TestValue() {}
func (*Data) TestPointer() {}
func main() {
var p *Data = nil
p.TestPointer()
// 这里是将 nil 转换成 *Data类型
(*Data)(nil).TestPointer() // method value
(*Data).TestPointer(nil) // method expression
// p.TestValue() // invalid memory address or nil pointer dereference
// (Data)(nil).TestValue() // cannot convert nil to type Data
// Data.TestValue(nil) // cannot use nil as type Data in function argument
}
网友评论