Go语言中并没有类(class),所以并不是纯粹的面向对象语言。大多数都是用函数、结构体实现。
func function_name([parameter list]) [return_types]{
函数体
}
func:函数由func开始声明
function_name:函数名称,函数名和参数列表一起构成了函数签名。
[parameter list]:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指
定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types:返回类型,函数返回一列值。return_types是该列值的数据类型。(非必须可以不加)
函数体:函数定义的代码集合。
Demo01
定义了两个函数add
累和,compare
比较最大值
package main
import "fmt"
func add(a int, b int) (sum int) {
sum = a + b
return sum
}
func compare(x int, y int) (max int) {
if x > y {
max = x
} else {
max = y
}
return max
}
func main() {
sum := add(2, 3)
fmt.Println(sum)
max := compare(2, 3)
fmt.Println(max)
}
若没设置retrun的返回内容,则根据返回类型返回值
package main
import "fmt"
func test() (name string, age int) {
name = "Sentiment"
age = 18
return //相当于return name, age
}
func main() {
a, b := test()
fmt.Println(a, b)
}
结果:
Sentiment 18
如果函数的最后一个参数是采用 ...type
的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变长函数。
Demo02
package main
import "fmt"
func add(nums ...int) (res int) {
for _, n := range nums {
res += n
}
return
}
func main() {
var result int
result = add(1, 2, 3)
fmt.Println(result)
}
//6
如果参数被存储在一个 切片类型的变量 slice
中,则可以通过 slice...
的形式来传递参数调用变参函数
package main
import "fmt"
func add(nums ...int) (res int) {
for _, n := range nums {
res += n
}
return
}
func main() {
var result int
slice := []int{7, 9, 3, 5, 1}
result = add(slice...)
fmt.Println(result)
}
//25
可以用type
关键字来定义函数的类型
type f1 func( int, int) int
定义了一个f1
函数类型,可以接受两个int
类型的参数并且返回一个int
类型的返回值
若定义一个与f1
函数类型相同的函数,则可以把该函数赋值给f1
,此时f1
就有了该函数的功能
Demo03
package main
import "fmt"
type f1 func(int, int) int
func sum(a int, b int) int {
return a + b
}
func max(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
func main() {
var f1 f1
f1 = sum //将sum函数赋值给f1类型的变量f1
s := f1(1, 2)
fmt.Println(s)
f1 = max //将max函数赋值给f1类型的变量f1
m := f1(3, 4)
fmt.Println(m)
}
结果:
3
4
其实就是函数回调。
package main
import "fmt"
func sayhello(name string) {
fmt.Printf("Hello,%s", name)
}
func test1(name string, f func(string2 string)) {
f(name)
}
func main() {
test1("Sentiment", sayhello)
}
所谓匿名函数就是没有名称的函数。
func(参数列表)(返回值)
Demo05
package main
import "fmt"
func main() {
max := func(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
i := max(1, 2)
fmt.Println(i)
}
//2
或者也可以直接调用自己
package main
import "fmt"
func main() {
func(a int, b int) {
max := 0
if a > b {
max = a
} else {
max = b
}
fmt.Println(max)
}(1, 2)
}
//2
闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)
Demo06
package main
import "fmt"
func addupper() func(x int) int {
n := 10
return func(x int) int {
n += x
return n
}
}
func main() {
f := addupper()
fmt.Println(f(1)) //11
fmt.Println(f(2)) //13
fmt.Println(f(3)) //16
}
代码说明,addupper是一个函数,返回数据类型是func (x int) int
闭包部分:
n := 10
return func(x int) int {
n += x
return n
返回的是一个匿名函数,但是这个匿名函数引用到函数外的n,因此这个匿名函数和n形成了一个整体,构成闭包。
请编写一个程序,具体要求如下:
package main
import (
"fmt"
"strings"
)
//- 编写一个函数makeSuffix(suffix string) 可以接收一个文件后缀名(如.jpg),并返回一个闭包
//- 调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(如.jpg),则返回文件名.jpg,如果已经有.jpg后缀,则返回文件名
//- 要求使用闭包的方式完成
func makeSuffix(suffix string) func(s string) string {
return func(s string) string {
if !strings.HasSuffix(s, suffix) {
return s + suffix
} else {
return s
}
}
}
func main() {
f := makeSuffix(".jpg")
x := f("Sentiment")
y := f("Sentiment.jpg")
fmt.Println(x)
fmt.Println(y)
}
结果:
Sentiment.jpg
Sentiment.jpg
也可以不用闭包实现,看下区别:
package main
import (
"fmt"
"strings"
)
func makeSuffix2(suffix string, s string) string {
if !strings.HasSuffix(s, suffix) {
return s + suffix
} else {
return s
}
}
func main() {
f1 := makeSuffix2(".jpg", "Sentiment") //设置后缀.jpg
f2 := makeSuffix2(".jpg", "Sentiment.jpg") //设置后缀.jpg
fmt.Println(f1)
fmt.Println(f2)
}
这种方式在调用时,每次都需要设置后缀.jpg,而闭包只需要设置一个 f := makeSuffix(".jpg")
即可
用个经典的斐波那契数列举例:
计算公式为f(n)=f(n-1)+f(n-2)
且f(2)=f( 1)=1
package main
import "fmt"
func main() {
fmt.Println(fib(4))
}
func fib(n int) (res int) {
if n == 1 || n == 2 {
res = 1
} else {
res = fib(n-1) + fib(n-2)
}
return res
}
//3
go语言中的defer语句会将其后面跟随的语句进行延迟
处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序
进行执行,也就是说,先被defer
的语句最后会被执行,最后被defer
的语句,最先被执行。
特性
defer
用于延迟调用retrun
前才被执行。因此,可以用来资源清理defer
语句,按先进后出的方式执行defer
语句中的变量,在defer
声明时就决定了用途
Demo08
package main
import "fmt"
func main() {
fmt.Println("start")
defer fmt.Println("step1")
defer fmt.Println("step2")
defer fmt.Println("step3")
fmt.Println("end")
}
结果:
start
end
step3
step2
step1
golang有一个特殊的函数init
函数,先于main
函数执行,实现包级别的一些初始化操作。
特点
初始化顺序
顺序:变量初始化 -> init() -> main()
Demo09
package main
import "fmt"
var a int = initVar()
func init() {
fmt.Println("init2")
}
func init() {
fmt.Println("init")
}
func initVar() int {
fmt.Println("init var...")
return 100
}
func main() {
fmt.Println("main...")
}
结果:
init var...
init2
init
main...