基本语法
GoLang的函数声明,返回类型写在最后,确实不符合我以前的习惯,因为我C和Java用得多,这两种语言,返回类型都是写在函数/方法名前面的,不过不习惯也得练习适应啊。
package main
import "fmt"
func main() {
fmt.Println(cubic(3))
}
func cubic(x rune) rune {
return x * x * x
}
执行结果:
27
所以可以总结下函数的声明就是这么几部分组成:
- func关键字
- 函数名
- 参数列表
- 返回值列表
- 函数体
多返回值
多返回值,我在python里已经体验过了,但是Python的多返回值是将返回值包装为元组,如果拿多个变量来接,就把元组拆开,再赋值到多个变量。Go的多返回值函数,是必须得全部接全部返回值,如果不需要用那么多返回值,就需要用下划线来占位,如。
package main
import "fmt"
func main() {
a, _ := divmod(7, 3)
fmt.Println(a)
}
func divmod(x rune, y rune) (rune, rune) {
return x / y, x % y
}
输出:
2
一等公民
在Go里函数是一等公民,是一个特殊的类型。最明显的是可以将一个变量定义为函数类型,这样程序的灵活性大大提高,或者说将函数赋值给一个变量。我举个例子,我用一个函数产生抛物线函数,然后调用抛物线函数:
package main
import "fmt"
func main() {
fun := parabola(3, 4, 5)
fmt.Println(fun(3))
}
func parabola(a rune, b rune, c rune) func(rune) rune {
return func(x rune) rune {
return a*x*x + b*x + c
}
}
上述代码执行结果为:
44
匿名函数
其实上面的例子里已经有了匿名函数了。上例的匿名函数是在函数体内定义的。能否在包下定义呢?是可以的,但是只能定义为变量,不能定义为常量,如:
package main
import "fmt"
var porabola = func(x rune) rune {
return 3*x*x + 4*x + 5
}
func main() {
fmt.Println(porabola(6))
}
执行结果:
137
其实我还忘了介绍匿名函数的一个特性,就是匿名函数如果在函数体内定义,可以直接调用局部变量,并且可以修改局部变量的值。这点和java不一样,java的匿名内部类和lambda表达式是不能修改局部变量的值的。对于GoLang的这点,我举个例子:
package main
import "fmt"
func main() {
x := 1
increment := func() {
x++
}
increment()
fmt.Println(x)
}
执行以后,输出为2,说明x已经加1了。
可变参数
许多编程语言有变长参数,最明显的是C语言的printf函数,java也有三个点号的函数定义。而Python就更复杂了,有两种形式的,*args和**kwargs。在GoLang中,这类函数叫Variadic Functions,fmt包下的Println就是这样的函数。这样的函数我们也可以写一个练练,不过需要提前学习下for循环语法了。我是写了一个连乘函数练手哈:
package main
import "fmt"
func main() {
fmt.Println(prod(3, 4, 5, 6, 7))
}
func prod(vars ...rune) rune {
var p rune = 1
for _, v := range vars {
p *= v
}
return p
}
输出结果:
2520
返回值命名
这是goLang语言特殊的地方,其他的编程语言,函数或方法定义返回值的时候只需要定义类型就可以了。GoLang也可以只定义返回值的类型,但是GoLang可以同时定义返回值的变量名。指定了变量名,那就意味着定义了变量,同时也意味着函数返回时只需要一个简单的return,return关键字后不需要再加任何变量了。我举个例子:
package main
import "fmt"
func main() {
fmt.Println(multiply(3, 5))
}
func multiply(a rune, b rune) (c rune) {
c = a * b
return
}
输出结果是15,因为在返回值列表里已经定义了返回值变量,所以return后面什么都不用写。但是这个return能不能省略呢?这是不可以的!会报语法错误。
init函数
init函数和main函数应该一起讲的,但是main函数大家已经很熟悉了,所以只需要单独说说init函数,init函数在go文件里会在main函数之前执行,如以下例子:
package main
import "fmt"
func init() {
fmt.Println("init")
}
func main() {
fmt.Println("Hello, world!")
}
输出结果为:
init
Hello, world!
确实验证了init在main函数之前执行。
注意事项
- 在学JSON那里我们会看到只有首字母大写的字段才能JSON序列化和反序列化。这是GoLang的做法,首字母大写的才是公有的,才能被其他包访问到,函数也是一样,如果希望函数被其他包调用,首字母应当大写。
- GoLang的函数不支持重载。