go函数作为一等民
定义函数类型
声明函数类型的变量和为变量赋值
package main
import "fmt"
type Operation func(a, b int) int
func Add(a, b int) int {
return a + b
}
func main() {
var op Operation
op = Add
fmt.Println(op(1, 2))
}
高阶函数
函数作为其他函数入参
package main
import "fmt"
type Operation func(a, b int) int
func Add(a, b int) int {
return a + b
}
type Calculator struct {
v int
}
func (c *Calculator) Do(op Operation, a int) {
c.v = op(c.v, a)
}
func main() {
var calc Calculator
calc.Do(Add, 1)
fmt.Println(calc.v)
}
函数作为返回值加动态创建函数
import "fmt"
type Operation func(b int) int
func Add(b int) Operation {
addB := func(a int) int {
return a + b
}
return addB
}
func main() {
add := Add(2)
i := add(3)
fmt.Println(i)
}
package main
import "fmt"
type Operation func(b int) int
func Add(b int) Operation {
addB := func(a int) int {
return a + b
}
return addB
}
type Calculator struct {
v int
}
func (c *Calculator) Do(op Operation) {
c.v = op(c.v)
}
func main() {
var calc Calculator
calc.Do(Add(1))
fmt.Println(calc.v)
}
匿名函数
package main
import "fmt"
type Operation func(b int) int
func Add(b int) Operation {
return func(a int) int {
return a + b
}
}
闭包
闭包是指有权访问另一个函数作用域中变量的函数,不需要传值。闭包一定是在一个函数内部的,但是闭包不等于匿名函数。
一个函数可以是匿名函数,但可以不是闭包。
闭包副作用
func main() {
s1 := []int{1, 2, 3, 4}
for i, v := range s1 {
go func() {
println(i, v)
}()
}
time.Sleep(time.Second)
}
输出
3 4
3 4
3 4
3 4
这是为什么?
因为没有传值,所有所有的goroutine都共享i, v,go的调度始终不会快过顺序执行的代码。
如何修正?
func main() {
s1 := []int{1, 2, 3, 4}
for i, v := range s1 {
go func(i, v int) {
println(i, v)
}(i, v)
}
time.Sleep(time.Second)
}
此时的输出顺序取决于go的调度了,但是会将s1内的元素都输出出来
三个版本的p2p网络
版本1:使用锁保护共享数据
package main
import (
"fmt"
"sync"
)
type Peer struct {
ID string
}
func (p *Peer) WriteMsg(msg string) {
fmt.Printf("send to: %v, msg: %v\n", p.ID, msg)
}
type Host struct {
peers map[string]*Peer
lock sync.RWMutex
}
func NewHost() *Host {
h := &Host{
peers: make(map[string]*Peer),
}
return h
}
func (h *Host) AddPeer(p *Peer) {
h.lock.Lock()
defer h.lock.Unlock()
h.peers[p.ID] = p
}
func (h *Host) GetPeer(pid string) *Peer {
h.lock.Lock()
defer h.lock.Unlock()
return h.peers[pid]
}
func (h *Host) RemovePeer(pid string) {
h.lock.Lock()
defer h.lock.Unlock()
delete(h.peers, pid)
}
func (h *Host) BroadcastMsg(msg string) {
h.lock.Lock()
defer h.lock.Unlock()
for _, p := range h.peers {
p.WriteMsg(msg)
}
}
版本2:使用channel传递数据
package main
import "fmt"
type Peer struct {
ID string
}
func (p *Peer) WriteMsg(msg string) {
fmt.Printf("send to: %v, msg: %v\n", p.ID, msg)
}
type Host struct {
add chan *Peer
broadcast chan string
remove chan string
stop chan struct{}
}
func NewHost() *Host {
h := &Host{
add: make(chan *Peer),
broadcast: make(chan string),
remove: make(chan string),
stop: make(chan struct{}),
}
return h
}
func (h *Host) Start() {
go h.loop()
}
func (h *Host) Stop() {
close(h.stop)
}
func (h *Host) loop() {
peers := make(map[string]*Peer)
for {
select {
case p := <-h.add:
peers[p.ID] = p
case pid := <-h.remove:
delete(peers, pid)
case msg := <-h.broadcast:
for _, p := range peers {
p.WriteMsg(msg)
}
case <-h.stop:
return
}
}
}
func (h *Host) AddPeer(p *Peer) {
h.add <- p
}
func (h *Host) RemovePeer(pid string) {
h.remove <- pid
}
func (h *Host) BroadcastMsg(msg string) {
h.broadcast <- msg
}
func main() {
}
版本3:使用channel传递函数
package main
import "fmt"
type Peer struct {
ID string
}
func (p *Peer) WriteMsg(msg string) {
fmt.Printf("send to: %v, msg: %v\n", p.ID, msg)
}
type Operation func(peers map[string]*Peer)
type Host struct {
opCh chan Operation
stop chan struct{}
}
func NewHost() *Host {
h := &Host{
opCh: make(chan Operation),
stop: make(chan struct{}),
}
return h
}
func (h *Host) AddPeer(p *Peer) {
add := func(peers map[string]*Peer) {
peers[p.ID] = p
}
h.opCh <- add
}
func (h *Host) RemovePeer(pid string) {
rm := func(peers map[string]*Peer) {
delete(peers, pid)
}
h.opCh <- rm
}
func (h *Host) BroadcastMsg(msg string) {
broadcast := func(peers map[string]*Peer) {
for _, p := range peers {
p.WriteMsg(msg)
}
}
h.opCh <- broadcast
}
func (h *Host) GetPeer(pid string) *Peer {
retCh := make(chan *Peer)
query := func(peers map[string]*Peer) {
retCh <- peers[pid]
}
go func() {
h.opCh <- query
}()
return <- retCh
}
func (h *Host) loop() {
peers := make(map[string]*Peer)
for {
select {
case op := <-h.opCh:
op(peers)
case <-h.stop:
return
}
}
}
友情提醒:这3种方式本身并无优劣之分,具体要用那种实现,要依赖自身的实际场景进行取舍。
https://lessisbetter.site/2019/06/09/golang-first-class-function/
一个没有高级趣味的人。
email:hushui502@gmail.com