go的函数式编程

go里面函数是一等公民,可以作为参数,变量,返回值。 可实现高阶函数和闭包等功能

闭包实现求和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func adder() func(int) int {
sum := 0
return func(val int) int {
sum += val
return sum
}
}

type iAdder func(int) (int, iAdder)

func adder2(base int) iAdder {
return func(val int) (int, iAdder) {
return base + val, adder2(base + val)
}
}

func main() {
add := adder()
for i := 1; i < 10; i++ {
fmt.Printf("0 - %d 的和为:%d \n", i, add(i))
}
}

菲波那切数列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func fabnqie() intGen {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}

type intGen func() int

func (g intGen) Read(p []byte) (n int, err error) {
next := g()
if next > 10 {
return 0, io.EOF
}
s := fmt.Sprintf("%d\n", next)
return strings.NewReader(s).Read(p)
}

func printContent(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}

func main(){
f := fabnqie()
printContent(f)
}

方法表达式

instance.method(args…) —> .func(instance, args…)

前者称为 method value,后者 method expression。
两者都可像普通函数那样赋值和传参,区别在于 method value 绑定实例,而 method expression 则须显式传参。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type User struct {
id int
name string
}

func (self *User) Test() {
fmt.Printf("%p, %v\n", self, self)
}

func main() {
u := User{1, "Tom"}
u.Test() // 0xc42000a060, &{1 Tom}

mValue := u.Test
// 隐式传递 receiver
mValue() // 0xc42000a060, &{1 Tom}

mExpression := (*User).Test
// 显式传递 receiver
mExpression(&u) // 0xc42000a060, &{1 Tom}


u2 := User{1, "Tom"}
m2Value := u.Test // 立即复制 receiver,因为不是指针类型,不受后续修改影响。

u2.id, u2.name = 2, "Jack"
u2.Test() // {2 Jack}

m2Value() // {1 Tom}
}

在汇编层面,method value 和闭包的实现方式相同,实际返回 FuncVal 类型对象。

学习两种赋值方式

1
2
3
4
a := (*interface{})(nil) // 类似于 int(16.5)

var c interface{}
c = (*interface{})(nil)

a现在是啥?

(*interface{})(nil) 意思是把nil 类型转换为 *interface{}类型

a相当于 var a *interface{} = nil
a是个指针, 指向了nil, 所以a是nil

c现在是啥 ?

c是 interface{} 类型 , 这个类型有两个属性 , type和data,

c的type属性是*interface{},有值
c的data属性是nil,无值

只有当type和data都是nil时, 空接口才是nil, 所以c不是nil

1
2
3
4
5
a := (*interface{})(nil)
log.Printf("%v\n", a == nil) // true
var c interface{}
c = (*interface{})(nil)
log.Printf("%v\n", c == nil) // false