一、基本说明:
Golang 中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型, 都可以有方法,而不仅仅是 struct。也就是方法可以在任意数据类型上面定义。
方法定义的语法:
func (变量名 type) 方法名(参数列表) (返回值列表){
//方法体
return 返回值
}
示例如下:
type Student struct {
Name string
Age int
}
// 定义方法,只能Student类型的实例调用。//这里 s 变量相当于其他语言的this。
func (s Student) test() {
fmt.Println(s) // {张三 20}
}
func main() {
var stu = Student{"张三",20}
stu.test() //调用test() 方法
}
说明:
1、func (s Student) test(){ //方法体 } 这里的
(s Student)
表示给Student类型绑定了一个方法test()。并且变量名 s 可以在方法体内使用。2、s 变量就是调用这个方法的实例作为参数传递进来,也区分值传递、引用传递。struct是值传递。所以s是一个拷贝。和函数传递参数特征一样。
1.1.1. 二、示例2:给Student类型添加一个求和方法。
type Student struct {
Name string
Age int
}
//给Student绑定一个求和方法 add 。
func (s Student) add(n1 int, n2 int) int {
return n1 + n2
}
func main() {
var stu = Student{"张三",20}
sum := stu.add(10, 90) //调用方法
fmt.Println(sum) // 100
}
1.1.2. 三、使用方法的注意事项。
1、如果给结构体绑定方法,希望在方法中修改调用这个方法的实例的属性值,可以传递指针。
实际操作中如果给结构体struct绑定方法,因为struct是值类型,传参和变量赋值是拷贝,因此更多的是传递struct指针,防止拷贝。
type Student struct {
Name string
Age int
}
//给Student绑定一个modify()方法。
func (s *Student) modify() {
s.Name = "wang5" //改变name的值 等价于 (*s).Name = "wang5"
}
func main() {
var stu = Student{"张三",20}
//调用方法
stu.modify() //等价于 (&stu).modify()
fmt.Println(stu) // {wang5 20} 方法内修改影响了外部变量stu
}
说明:
stu.modify() 等价于 (&stu).modify()
s.Name = "wang5" 等价于 (*s).Name = "wang5"
这个是编译器底层做优化实现的。
2、自定义类型都可以有方法,而不仅仅是 struct, 比如 int , float32 等都可以有方法。
type Myint int
// 给 Myint 类型绑定方法
func (num Myint) test() {
fmt.Println(num) //9
}
func main() {
var num1 Myint = 9
num1.test()
}
其实
type Myint int
就是定义了一种新的类型Myint,给自定义类型加方法是可以的。
3、方法名首字母小写,只能在本包访问;方法首字母大写,可以在本包和其它包访问。
4、如果一个类型实现了 String()这个方法,那么 fmt.Println 默认会调用这个变量的 String()进行输出。
type Student struct {
Name string
Age int
}
func (stu Student) String() string {
str := fmt.Sprintf("name = %v,age = %v",stu.Name,stu.Age)
return str
}
func main() {
s := Student{"张三",12}
// 自动调用Student类型的String()方法
fmt.Println(s) //name = 张三,age = 12
}
1.1.3. 四、方法和函数区别。
1、调用方式不一样。
函数的调用方式: 函数名(实参列表)
方法的调用方式:变量.方法名(实参列表)
2、方法前面的绑定类型,可以是某类型或者他的指针类型。调用的时候可以使用这个类型的实例或指针调用。(仅限方法前面的绑定类型,函数的参数、方法后面的参数需要保持参数类型严格一致。)
例如如下:无论方法直接绑定某类型,还是它的指针类型,都可以使用这个类型的实例或指针直接调用。
type Student struct {
Name string
}
// 绑定指针类型 *Student
func (s *Student) test1() {
fmt.Println("test1.....")
}
// 绑定类型 Student
func (s Student) test2() {
fmt.Println("test2.....")
}
func main() {
var stu = Student{"张三"}
stu.test1() // 调用成功
(&stu).test1() // 调用成功
stu.test2() // 调用成功
(&stu).test2() // 调用成功
}
注意:无论怎么调用,因为Student 是struct。所以(s *Student) 都是引用传递,(s Student) 都是值拷贝。
3、特别注意一点。无论任何地方,都可以使用指针名点变量
获取到属性的值。
type Student struct {
Name string
}
func (s *Student) test1(s2 *Student) {
var name string = s2.Name; // 取得学生名
fmt.Println("test1.....",name)
}
func test2(s *Student) {
var name string = s.Name; // 取得学生名
fmt.Println("test2.....",name)
}
func main() {
var stu = Student{"张三"}
var name string = (&stu).Name
fmt.Println(name) //张三
stu.test1(&stu)
test2(&stu)
}
上面例子中,main方法内使用(&stu).Name 获得属性值。方法test1、函数test2 的指针参数点Name都可以获取属性值。