本文共 4574 字,大约阅读时间需要 15 分钟。
Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集
方法只是一个函数,它带有一个特殊的接收器类型,它是在func关键字和方法名之间编写的。接收器可以是struct类型或非struct类型。接收方可以在方法内部访问。
定义方法的语法
func (t Type) methodName(parameter list) { }
实例代码:
package mainimport ( "fmt")type Employee struct { name string salary int currency string}/* displaySalary() method has Employee as the receiver type*/func (e Employee) displaySalary() { fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)}func main() { emp1 := Employee { name: "Sam Adolf", salary: 5000, currency: "$", } emp1.displaySalary() //Calling displaySalary() method of Employee type}
可以定义相同的方法名
示例代码:
package mainimport ( "fmt" "math")type Rectangle struct { width, height float64}type Circle struct { radius float64}func (r Rectangle) area() float64 { return r.width * r.height}//该 method 属于 Circle 类型对象中的方法func (c Circle) area() float64 { return c.radius * c.radius * math.Pi}func main() { r1 := Rectangle{ 12, 2} r2 := Rectangle{ 9, 4} c1 := Circle{ 10} c2 := Circle{ 25} fmt.Println("Area of r1 is: ", r1.area()) fmt.Println("Area of r2 is: ", r2.area()) fmt.Println("Area of c1 is: ", c1.area()) fmt.Println("Area of c2 is: ", c2.area())}
运行结果
Area of r1 is: 24Area of r2 is: 36Area of c1 is: 314.1592653589793Area of c2 is: 1963.4954084936207
既然我们已经有了函数,为什么还要使用方法?
示例代码:
package mainimport ( "fmt")type Employee struct { name string salary int currency string}/* displaySalary() method converted to function with Employee as parameter*/func displaySalary(e Employee) { fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)}func main() { emp1 := Employee{ name: "Sam Adolf", salary: 5000, currency: "$", } displaySalary(emp1)}
在上面的程序中,displaySalary方法被转换为一个函数,而Employee struct作为参数传递给它。这个程序也产生了相同的输出:Salary of Sam Adolf is $5000.。
为什么我们可以用函数来写相同的程序呢?有以下几个原因
作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
Go 语言中变量可以在三个地方声明:
局部变量
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
全局变量
在函数体外声明的变量称之为全局变量,首字母大写全局变量可以在整个包甚至外部包(被导出后)使用。
package mainimport "fmt"/* 声明全局变量 */var g intfunc main() { /* 声明局部变量 */ var a, b int /* 初始化参数 */ a = 10 b = 20 g = a + b fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)}
结果
结果: a = 10, b = 20 and g = 30
形式参数
形式参数会作为函数的局部变量来使用
指针作为接收者
若不是以指针作为接收者,实际只是获取了一个copy,而不能真正改变接收者的中的数据
func (b *Box) SetColor(c Color) { b.color = c}
示例代码
package mainimport ( "fmt")type Rectangle struct { width, height int}func (r *Rectangle) setVal() { r.height = 20}func main() { p := Rectangle{ 1, 2} s := p p.setVal() fmt.Println(p.height, s.height)}
结果
20 2
如果没有那个*,则值就是2 2
method是可以继承的,如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method
package mainimport "fmt"type Human struct { name string age int phone string}type Student struct { Human //匿名字段 school string}type Employee struct { Human //匿名字段 company string}func (h *Human) SayHi() { fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)}func main() { mark := Student{ Human{ "Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{ Human{ "Sam", 45, "111-888-XXXX"}, "Golang Inc"} mark.SayHi() sam.SayHi()}
运行结果:
Hi, I am Mark you can call me on 222-222-YYYYHi, I am Sam you can call me on 111-888-XXXX
package mainimport "fmt"type Human struct { name string age int phone string}type Student struct { Human //匿名字段 school string}type Employee struct { Human //匿名字段 company string}//Human定义methodfunc (h *Human) SayHi() { fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)}//Employee的method重写Human的methodfunc (e *Employee) SayHi() { fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone) //Yes you can split into 2 lines here.}func main() { mark := Student{ Human{ "Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{ Human{ "Sam", 45, "111-888-XXXX"}, "Golang Inc"} mark.SayHi() sam.SayHi()}
运行结果:
Hi, I am Mark you can call me on 222-222-YYYYHi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX
转载地址:http://xmwji.baihongyu.com/