Go——函数与方法的奇妙之处

有过(面向对象)编程经验的应该都知道方法或者函数,比如在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上。

坚持原创技术分享,您的支持将鼓励我继续创作!