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/

posted @ 2020-06-30 13:48  zhangyu63  阅读(184)  评论(0编辑  收藏  举报