方法介绍
Golang 方法总是绑定对象实例,并隐式将实例作为第一实参。一个方法就是一个包含了参数的函数,参数可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。方法特征如下:
• 只能为当前包内命名类型定义方法。
• 参数 receiver 可任意命名。如方法中未曾使用 ,可省略参数名。
• 参数 receiver 类型可以是 T 或 *T。基本类型 T 不能是接口或指针。
• 不支持方法重载,receiver 只是参数签名的组成部分。
• 可用实例 value 或 pointer 调用全部方法,编译器自动转换。
懂的人都知道这里的门道有多深
方法定义格式:
func (recevier type) methodName(参数列表)(返回值列表){} //参数和返回值可以省略
1.方法案例
package main
import "fmt"
//定义一个Users结构体
type User struct {
name string
age uint8
}
// 定义User的method01方法,无参数无返回
func (u User) m01(){}
// 定义User的m02方法,有参数无返回
func (u User) me02(age int){}
// 定义User的m03方法,有参数单返回值
func (u User) m03(age int) string{
return "age:"+string(age)
}
// 定义User的m04方法,有参数多返回值
func (u User) m04(age int) (string,error){
return "age:"+string(age),nil
}
// 定义User的m05方法,多参数多返回值
func (u User) m05(name string,age int) (string,error){
return "name:name"+name+",age:"+string(age),nil
}
func (u User) m06(){
fmt.Println("name:",u.name,",age:",u.age)
}
func M01(){
//值类型调用方法,注意:当接受者是指针时,即使用值类型调用那么方法内部也是对指针的操作
u1:=User{"张三",10}
u1.m06() // name: 张三 ,age: 10
//指针调用方法
u2:=&User{"李四",20}
u2.m06() // name: 李四 ,age: 20
}
// 验证值调用方法与指针调用方法的区别
func (u User) ValueTest(){
fmt.Printf("Value: %p\n", &u)
}
func (u *User) PointerTest() {
fmt.Printf("Pointer: %p\n", u)
}
func M02(){
u1:=User{"张三",10}
u2:=&u1
u1.ValueTest()
u1.PointerTest()
u2.ValueTest()
u2.PointerTest()
}
func main() {
M01()
M02()
}
函数与方法异同
和 Go 函数一样,Go 的方法也是以 func 关键字修饰的,并且和函数一样,也包含方法名(对应函数名)、参数列表、返回值列表与方法体(对应函数体)。
而且,方法中的这几个部分和函数声明中对应的部分,在形式与语义方面都是一致的,比如:方法名字首字母大小写决定该方法是否是导出方法;方法参数列表支持变长参数;方法的返回值列表也支持具名返回值等。
不过,它们也有不同的地方。从上面这张图我们可以看到,和由五个部分组成的函数声明不同,Go 方法的声明有六个组成部分,多的一个就是图中的 receiver 部分。在 receiver 部分声明的参数,Go 称之为 receiver 参数,这个 receiver 参数也是方法与类型之间的纽带,也是方法与函数的最大不同。
Go 中的方法必须是归属于一个类型的,而 receiver 参数的类型就是这个方法归属的类型,或者说这个方法就是这个类型的一个方法。以图中的 ListenAndServeTLS 为例,这里的 receiver 参数 srv 的类型为 *Server,那么我们可以说,这个方法就是 *Server 类型的方法。
函数与方法的区别在于:
- 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然。
- 对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。 懂的人都知道这里的门道有多深
2.匿名字段
Golang匿名字段可以像字段成员那样访问匿名字段方法,编译器负责查找。
package main
import "fmt"
type DogUser struct{
name string
age int
}
type DogManager struct{
DogUser //匿名字段,只有字段类型,没有字段名称
}
func (u *DogUser) ToString() string {
return fmt.Sprintf("User: %p, %v", u, u)
}
func callMethod03(){
d:=DogManager{DogUser{"Tom",2}}
fmt.Printf("Manager: %p\n", &d) // Manager: 0xc000004078
fmt.Println(d.ToString()) // User: 0xc000004078, &{Tom 2}
fmt.Println(d.name) // Tom
fmt.Println(d.age) // 2
}
func main(){
callMethod03()
}
案例一:计算矩形面积
type Rectangle struct {
width float64
height float64
}
func (r *Rectangle) Area() float64 {
return r.width * r.height
}
func main() {
rect := &Rectangle{width: 5, height: 10}
fmt.Println("矩形面积为:", rect.Area()) // 输出: 矩形面积为: 50
}
案例二:反转字符串
type StringUtil struct {
str string
}
func (s *StringUtil) Reverse() string {
runes := []rune(s.str)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
func main() {
strUtil := &StringUtil{str: "hello, world"}
fmt.Println("反转后的字符串为:", strUtil.Reverse()) // 输出: 反转后的字符串为: dlrow,olleh
}
那么恭喜你,完成了本次的go方法学习和练习