有过(面向对象)编程经验的应该都知道方法或者函数,比如在C,PHP,swift,OC,Java,kotlin等都有函数或者方法的存在,或者有二者的存在,只是有些人没有太过留意,比如PHP中就有这样的现象,而iOS中除了存在方法和行数,方法还分类方法和对象方法。
有过(面向对象)编程经验的应该都知道方法或者函数,比如在C,PHP,swift,OC,Java,kotlin等都有函数或者方法的存在,或者有二者的存在,只是有些人没有太过留意,比如PHP中就有这样的现象,而iOS中除了存在方法和行数,方法还分类方法和对象方法。
那么Golang中方法和行数的本质意义其实差不多,只是定义和使用的语法不同而已。
这里我们就来说说Golang中函数与方法,
函数:
行数定义
func function_name( [parameter list] ) [return_types]{
body of the function
}
不允许函数内嵌定义
func main() {
func swap(x, y string) (string, string) {
return y, x
}
}
支持多返回值、支持命名返回值
func split(sum int) (x, y int) {
return
}
函数只能判断是否为nil
fmt.Println(add == nil)
//fmt.Println(add == 1) //错误 mismatched types func(int, int) int and int)
参数视为局部变量,因此不能声明同名变量
func add(a, b int) int {
a := 2
}
不支持默认参数、已”_”命名的参赛也不能忽略
func add(a, b int, _ bool) int {
return a + b
}
func main() {
fmt.Println(add(1,2, true))
//fmt.Println(add(1,2) // 错误:not enough arguments in call to add
}
支持可变参数
func test(str string, a ...int) {
fmt.Println("%T, %v\n", str, a)
}
func main() {
test("a", 1, 2, 3)
}
可以在函数内定义匿名函数
func main() {
func (s string) {
fmt.Println(s)
} ("hello, go!")
}
闭包
// This function `intSeq` returns another function, which
// we define anonymously in the body of `intSeq`. The
// returned function _closes over_ the variable `i` to
// form a closure.
func intSeq() func() int {
i := 0
return func() int {
i += 1
return i
}
}
func main() {
// We call `intSeq`, assigning the result (a function)
// to `nextInt`. This function value captures its
// own `i` value, which will be updated each time
// we call `nextInt`.
nextInt := intSeq()
// See the effect of the closure by calling `nextInt`
// a few times.
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
// To confirm that the state is unique to that
// particular function, create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}
- 注意
- 函数的左花括号也不能另起一行
- 不支持函数重载
方法:
方法定义
func (r Recevier) function_name(){
body of the method
}
定义和使用:
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
下面来仔细看看官方对方法给出的一个例子
package main
import "fmt"
type rect struct {
width, height int
}
// This `area` method has a _receiver type_ of `*rect`.
func (r *rect) area() int {
return r.width * r.height
}
// Methods can be defined for either pointer or value
// receiver types. Here's an example of a value receiver.
func (r rect) perim() int {
return 2*r.width + 2*r.height
}
func main() {
r := rect{width: 10, height: 5}
// Here we call the 2 methods defined for our struct.
fmt.Println("area: ", r.area())
fmt.Println("perim:", r.perim())
// Go automatically handles conversion between values
// and pointers for method calls. You may want to use
// a pointer receiver type to avoid copying on method
// calls or to allow the method to mutate the
// receiving struct.
rp := &r
fmt.Println("area: ", rp.area())
fmt.Println("perim:", rp.perim())
}
其实是利用方法求长方形的周长和面积,其中也给出了receiver作为指针和值的区别
- 这里也简单说下:什么时候receiver用指针
- 1 改变receiver的值
- 2 struct本身非常的大,这样拷贝的代价是很昂贵的
- 3 如果struct的一个method中receiver为指针,那么其他的method的receiver最好也要用指针。
方法与函数的区别
在golang的世界中,一定要区分 方法和函数。
Go中没有类的概念,但是我们可以在一些类型上定义一些方法,也就是所谓的方法,跟函数不同。
- 方法和函数定义语法区别在于:
- 方法是针对对象的(有些是针对类)
- 函数是针对全局的(Golang中指包),
- 方法前置实例接受参数,这个receiver可以是基础类型也可以是指针。
虽然Go语言没有类的概念,但它支持的数据类型可以定义对应的method(s)。本质上说,所谓的method(s)其实就是函数,只不过与普通函数相比,这类函数是作用在某个数据类型上的,所以在函数签名中,会有个receiver(接收器)来表明当前定义的函数会作用在该receiver上。