e := errors.New("原始错误e")
w := fmt.Errorf("Wrap了一个错误%w", e)
C <-chan Time 用法
type Timer struct {
    C <-chan Time
    r runtimeTimer
}

C <-chan Time  表示C 是一个chan 类型,且chan 是只可读的,channel 中的类型是Time类型


 

将函数作为入参(回调函数),能带来便利。如日志处理,为了统一处理,将信息均通过指定函数去记录日志,且是否记录日志还有开关

func Log(title string, getMsg func() string) {
    //如果开启日志记录,则记录日志
    if true {
        fmt.Println(title, ":", getMsg())
    }
}
//---------调用--------------
count := 0
msg := func() string {
    count++
    return "您没有即使提醒我,已触犯法律"
}
Log("error", msg)
Log("warring", msg)
Log("info", msg)
fmt.Println(count)
package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}


 

golang结构体和类
interface即interface{}可以看作任意类型, 即C中的void *
v interface{}
 v.(string)		//类型转换
v.(net.Conn).Close()
解决:interface conversion: interface {} is float64, not int
w := video["width"]
h := video["height"]
if w != nil && h != nil {
        width := int(w.(float64))
        height := int(h.(float64))
        logger.Infof("width:%d, height:%d", width, height)
        if width != 0 && height != 0 {
                output.Dimensions = strconv.Itoa(width) + "x" + strconv.Itoa(height)
        }
}

4. go适合做什么

  • 服务端开发
  • 分布式系统,微服务
  • 网络编程
  • 区块链开发
  • 内存KV数据库,例如boltDB、levelDB
  • 云平台

1.1.5. 学习Go语言的前景

目前Go语言已经⼴泛应用于人工智能、云计算开发、容器虚拟化、⼤数据开发、数据分析及科学计算、运维开发、爬虫开发、游戏开发等领域。

Go语言简单易学,天生支持并发,完美契合当下高并发的互联网生态。Go语言的岗位需求持续高涨,目前的Go程序员数量少,待遇好。

抓住趋势,要学会做一个领跑者而不是跟随者。

国内Go语言的需求潜力巨大,目前无论是国内大厂还是新兴互联网公司基本上都会有Go语言的岗位需求。

Go语言GOPATH详解(Go语言工作目录)

在Windows上安装Go语言开发包

Goland入门指南(使用Goland创建并运行项目)
	//my_json "baseline_client/json"   旧写法
	my_json "github.com/angeek/bclient/json"

1. 通道channel

ch <- v    // 发送值v到Channel ch中
v := <-ch  // 从Channel ch中接收数据,并将数据赋值给v
chan的分类
分为带缓存和不带缓存这2类,尤其需要关注带缓存的用法,防止掉坑里。
不带缓存 
make(chan 数据类型)

带缓存 
make(chan 数据类型,长度)
例如定义一个带缓存的chan: ch := make(chan int,2) 
这里我们定义个缓存长度为2的chan,当我们已经往chan中写入了2个数据,当再次写入第三个数据的时候就会发送阻塞,直到其他人从该chan中读取了数据,那么才可以再次写入数据,带缓存的chan类似于一个队列,当队列满的时候是无法写入数据的。 
3. chan的关闭



	if runtime.GOOS == "windows" {
		path = string(path[0 : strings.LastIndex(path, "\\")])
	} else {
		path = string(path[0 : strings.LastIndex(path, "/")])
	}

chan十分类似我们Python中的队列Queue不是吗?

其实,缓冲信道是先进先出的,我们可以把缓冲信道看作为一个线程安全的队列:

ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
for v := range ch {
    fmt.Println(v)
    if len(ch) <= 0 { // 如果现有数据量为0,跳出循环
        break
    }
}



close(ch)
被关闭的信道会禁止数据流入, 是只读的。我们仍然可以从关闭的信道中取出数据,但是不能再写入数据了。

无缓冲的信道是一批数据一个一个的「流进流出」
缓冲信道则是一个一个存储,然后一起流出去

2. 切片

 切片简介

数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型Slices切片(“动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。 

append函数将x追加到切片s的末尾,并且在必要的时候增加容量。
a := make([]int, 1)
// a == []int{0}
a = append(a, 1, 2, 3)
// a == []int{0, 1, 2, 3}


s := arr[startIndex:endIndex] 
将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片


var counters []IOCountersStat
counters = append(counters, c)

3. make

返回指针数组
fun a()([]*url.URL, error){
u := new(URL)

return []*url.URL{u}, nil
}


 

务必记得 make 仅适用于 map,slice 和 channel,并且返回的不是指针。应当用 new 获得特定的指针。
    var p *[] int = new ([] int ) //← 分配 slice 结构内存;很少使用
    var v [] int = make ([] int , 100) //← v 指向一个新分配的有 100 个整数的数组
    //==========================
    var p *[] int = new ([] int ) //← 不必要的复杂例子
    *p = make ([] int , 100, 100)
    //==========================
    v := make ([] int , 100) //← 更常见    


make 只能为 slice、map或 channel 类型分配内存并初始化,同时返回一个有初始值的 slice、map 或 channel 类型引用,不是指针。具体如何使用 make 呢,官网中 https://golang.org/ref/spec#Making_slices_maps_and_channels 有介绍
对于make slice而言,有两个概念需要搞清楚:长度跟容量。
容量表示底层数组的大小,长度是你可以使用的大小。
容量的用处在哪?在与当你用 appen d扩展长度时,如果新的长度小于容量,不会更换底层数组,否则,go 会新申请一个底层数组,拷贝这边的值过去,把原来的数组丢掉。也就是说,容量的用途是:在数据拷贝和内存申请的消耗与内存占用之间提供一个权衡。
而长度,则是为了帮助你限制切片可用成员的数量,提供边界查询的。所以用 make 申请好空间后,需要注意不要越界【越 len 】

切片增长不能超出其容量。增长超出切片容量将会导致运行时异常,就像切片或数组的索引超出范围引起异常一样。同样,不能使用小于零的索引去访问切片之前的元素。

4. string

upper := strings.ToUpper(strData)  //将小写变大写
_, err = conn.WriteToUDP([]byte(upper), rAddr)  //将string转为切片[]byte

既然string就是一系列字节,而[]byte也可以表达一系列字节,那么实际运用中应当如何取舍?

  • string可以直接比较,而[]byte不可以,所以[]byte不可以当map的key值。
  • 因为无法修改string中的某个字符,需要粒度小到操作一个字符时,用[]byte。
  • string值不可为nil,所以如果你想要通过返回nil表达额外的含义,就用[]byte。
  • []byte切片这么灵活,想要用切片的特性就用[]byte。
  • 需要大量字符串处理的时候用[]byte,性能好很多。

最后脱离场景谈性能都是耍流氓,需要根据实际场景来抉择。

参考链接

Golang也支持面向对象编程。但与以前学过传统的面向对象编程语言有区别。
1)Golang没有类class,Go语言的结构体struct和类class有相似的特性。
2)Golang中不存在继承,方法重载,构造函数,析构函数,隐藏和this指针。
3)Golang有继承,封装,多态的特性,但是实现方法与传统OOP语言不同。

数组

动态数组应该这样写
array := make([]int, length)

出现线程安全问题,可以使用sync包或者goroutine和channel来解决这个问题。

switch case

go的switch case默认有break。如果不需要break,可以加上fallthrough

反射:可以在运行时动态获取变量的相关信息 
Import (“reflect”)

golang 获取一个结构体 struct 大小的代码 回调函数
package main
import "fmt"
 
type Callback func (x, y int) int
 
//提供一个接口,让外部去实现
func test(x, y int, callback Callback) int {
  return callback(x, y)
}
 
func add(x, y int) int {
  return x + y
}
 
func main() {
  x, y := 6, 7
  z := test(x, y, add)	
  fmt.Printf("z = %d",z)
}
Golang接口----flag.Parse()

flag.Value接口的用法,我们看到的很多代码如果使用了flag包那么它的主函数中总会有flag.Parse(),这个函数的主要是把用户传递的命令行参数解析为对应变量的值。可能会有些人比较疑惑,这句话什么意思我们来看一下代码就好,但在看代码之前我们先来了解一下命令行传参的格式: