在go中,函数类型是一等类型,这意味着可以吧函数当做一个值来传递和使用。
func divide(dividend int,divisor int)(int,error){ //省略部分代码 }
参数列表中的参数必须有名称,结果列表中结果的名称可有可无(要么都省略名称,要么都有名称)。
func divide(dividend int,divisor int)(result int, err error){ //省略部分代码 }
函数体中每个条件分支的最后一般都要有return语句,“return 返回值” , 若函数声明的结果是有具体名字的,那么return关键字后面就不用追加任何东西了, “return”
func divide(dividend int,divisor int)(result int, err error){ if divisor ==0{ err = erros.New("division by zero") return } result = dividend / divisor return }
完整实例
package main import ( "errors" "fmt" ) func divide(dividend int, divisor int) (result int, err error) { if divisor == 0 { err = errors.New("division by zero") return } result = dividend / divisor return } func main() { re, err := divide(5, 3) if err != nil { fmt.Println(err) } else { fmt.Println(re) } }
函数的零值是nil, 检查外来函数值是否非nil总是有必要的。
方法是函数的一种,它实际上就是与某个数据类型关联在一起的函数。 示例如下
package main import ( "fmt" ) type myInt int func (i myInt) add(another int) myInt { i = i + myInt(another) return i } func main() { i1 := myInt(1) i2 := i1.add(2) fmt.Println(i1, i2) }
从声明上看,方法只是在关键字func和函数名之间,加了一个由圆括号包裹的接收者声明。
接收者声明由两个部分组成
1)右边:表明了这份方法与哪个类型关联,这里是myInt;
2)左边:指定这个类型的值在当前方法中的标识符,这里是i, 这个标识符在当前方法中可以看做一个变量的代表,就像参数那样,可称为接收者变量。
注意:这个函数输出值是1 3
i的值未改变,是因为在值方法中对接收者变量的赋值一般不会影响到源值。i1的值就是源值。在调用i1的add方法时,这个值被赋给了接收者变量i(前者的副本与后者产生关联),但是,i和i1是两个变量,它们并不存在关联。
值方法的接收者类型是非指针的数据类型。相对应的是指针方法。它的接收者类型是某个数据类型的指针类型。
package main import ( "fmt" ) type myInt int func (i *myInt) add(another int) myInt { *i = *i + myInt(another) return *i } func main() { i1 := myInt(1) i2 := i1.add(2) fmt.Println(i1, i2) }
执行结果 3 3
值方法和指针方法遵循如下规则:
接收者变量代表的值实际上是源值的一个复制品。如果这个值不是指针类型的,那么值方法中自然就没有途径去修改源值。
而指针值与其复制值指向的肯定是同一个值,所以在指针方法中就存在了改变源值的途径。
这里有一个例外,那就是如果接收者类型是某个引用类型或它的别名类型,那么即使是值方法,也可以改变源值。
对于某个非指针的数据类型,与它关联的方法的集合中只包含了它的值方法。
而对于它的指针类型,其方法集合中即包含值方法也包含指针方法,不过,在非指针数据类型的值上,也是能够调用其指针方法的。这是因为在go的内部做了自动转换
例如,若add方法是指针方法,那么表达式i1.add(2)会被自动转换为(&i1).add(2)