码迷,mamicode.com
首页 > 其他好文 > 详细

GoStudy基础小册

时间:2020-08-26 17:13:37      阅读:54      评论:0      收藏:0      [点我收藏+]

标签:全局   lag   next   rate   断言   main   容量   链表   group   

一、基本数据类型

1 整型

分为int、uint,uint8byte型,int16对应C中的short型,int64

对应long型

2 特殊整型

uintptr 无符号整型,用于存放一个指针

3 浮点型

float32和float64

4 复数

complex64和complex128

5 byte和rune类型

uint8就是byte类型,代表ASCII码的一个字符,uint32就是rune类型,代表一个UTF字符

rune用来处理非英文,如汉语、日语

// 这样
func main() {
	s := "二哈"
	runes := []rune(s)
	fmt.Println(string(runes))
}
// 或者这样
func main() {
    s := "二哈"
    bytes := []byte(s)
    for len(bytes) > 0 {
        ch, size := utf8.DecodeRune(bytes)
        bytes = bytes[size:]
        fmt.Printf("%c ", ch)
    }
}

6 类型转换

var a, b = 3, 4
var c int
// math.Sqrt()接收的参数是float64类型,需要强制转换
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)

7 bool类型

和其他语言一样

8 枚举

枚举使用iota,这玩意默认值是0,下面的默认值是1什么鬼?

const (
   FlagNone = 1 << iota
   FlagRed     // iota=1 2 << iota
   FlagGreen   // iota=1 3 << iota
   FlagBlue    // iota=1 4 << iota
)

func main() {
   fmt.Printf("%d %d %d %d\n", FlagNone, FlagRed, FlagGreen, FlagBlue)
}
// 2 4 8

package main
import (
    "fmt"
)

type Byte float64
const (
    _ = iota
    KB Byte = 1 << (10*iota)    //iota自动+1,此时值为2,即 1 << (10*2)
    MB    //表达式自动重复, 1 << (10*iota)  即 1 << (10*3)
    GB    //...
    TB
    PB
    EB
    ZB
    YB
)

func (b Byte) String() string {
    switch {
        case b > YB:
            return fmt.Sprintf("%.2fYB", b/YB)
        case b > ZB:
            return fmt.Sprintf("%.2fZB", b/ZB)
        case b > EB:
            return fmt.Sprintf("%.2fEB", b/EB)
        case b > PB:
            return fmt.Sprintf("%.2fPB", b/PB)
        case b > TB:
            return fmt.Sprintf("%.2fTB", b/TB)
        case b > GB:
            return fmt.Sprintf("%.2fGB", b/GB)
        case b > MB:
            return fmt.Sprintf("%.2fMB", b/MB)
        case b > KB:
            return fmt.Sprintf("%.2fKB", b/KB)
    }
    return fmt.Sprintf("%.2fB", b)

}
func main() {
    var x Byte
    x = 1024*1024*1024 * 15
    fmt.Println(x)
    x = 1024*1024*1024*1024*1024 * 42
    fmt.Println(x)
}

//15.00GB
//42.00PB


package main
import "fmt"
const (
    A, B int = iota, iota+1
    _, _
    C, D
    E int = iota+10
)
func main() {
    fmt.Println(A, B, C, D, E)
}
//0 1 2 3 13

9 指针

ptr := &v,v的类型为T,v代表被取地址的变量,ptr的类型为*T,*代表指针

二、list

列表是使用container/list包来实现的,内部原理是双向链表

1 初始化:

  1. var lst list.List()
  2. lst := list.New()

2 添加:

lst.PushBack("aaa") //尾部

lst.PushFront("bbb") // 头部

3 插入:

element := lst.PushBack("aaa") //尾部添加后保存元素句柄

lst.InsertAfter("111", element)

lst.InsertBefore("222", element)

4 删除:

lst.Remove(element)

5 遍历:

for i := lst.Front(); i != nil; i = i.Next() {fmt.println(i.value)}

三、数组

1 定义:var a [3]int,定义一个长度为3元素类型为int的数组a,[3]int和[4]int类型不同

2 三种初始化:

  1. var b = [3]int{1, 2, 3}
  2. var b = [...]int{1, 2, 3}
  3. var b = [...]int{1: 1, 2: 2, 3: 3} // 指定下标

3 两种遍历:

  1. for i :=0; i < len(b); i++ {...}
  2. for index, value := range b {....}

4 多维数组:

var b = [3][2]{{1, 2}, {3, 4}, {5, 6}}

var b = [...][2]{{1, 2}, {3, 4}, {5, 6}} //多维数组只有第一层可以使用...来让编译器推导数组长度

四、切片

1 定义:var a []int

2 初始化:

  1. var a = []int{}
  2. a := make([int, size, cap])

3 切片的长度和容量:len()、cap()

切片不能直接比较,合法比较是和nil做比较,判断是否为空,用len(a) == 0

3 遍历:for、for range

4 复制切片:

copy(),切片是应用类型,直接赋值拷贝,若是修改会改变原有切片,所以用copy

4 切片添加元素:

append()

a = append(a, element) // 添加一个元素

a = append(a, elements...) //添加多个元素

5 删除元素:

append(),没有特定的删除方法,还是用使用切片本身的特性

  • 从头位置删除

a = []int{1,2,3}

a = a[1:] // 删除开头1个元素 a = a[N:] // 删除开头N个元素 a = append(a[:0], a[1:]...) // 删除开头1个元素 a = append(a[:0], a[N:]...) // 删除开头N个元素

用 copy() 函数来删除开头的元素

a = a[:copy(a, a[1:])] // 删除开头1个元素 a = a[:copy(a, a[N:])] // 删除开头N个元素

  • 从中间位置删除

a = append(a[:i], a[i+1:]...) // 删除中间1个元素 a = append(a[:i], a[i+N:]...) // 删除中间N个元素 a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素 a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素

  • 从尾部删除

a = a[:len(a)-1] // 删除尾部1个元素 a = a[:len(a)-N] // 删除尾部N个元素

多维切片同理

五、map

1 定义:map[key][value]==>map[int][int],类型变量默认为nil,要用make初始化才能使用

2 初始化:m := make(map[string][interface{}])

3 遍历:for range

4 删除键值对:

delete(m, key)

5 判断某个key是否存在:

value, ok := map[key],ok为true存在,false不存在

6 map不是线程安全的,并发使用sync.Map:

package main
import (
      "fmt"
      "sync"
)
func main() {
    var scene sync.Map
    // 将键值对保存到sync.Map
    scene.Store("red", 1)
    scene.Store("blue", 3)
    scene.Store("green", 2)
    // 从sync.Map中根据键取值
    fmt.Println(scene.Load("red"))
    // 根据键删除对应的键值对
    scene.Delete("red")
    // 遍历所有sync.Map中的键值对
    scene.Range(func(k, v interface{}) bool {
        fmt.Println("iterate:", k, v)
        return true
    })
}

六、结构体

1 自定义类型

type MyString string // 将MyString定义为string类型,MyString是一种新的类型,具有string的特性

2 类型别名

type byte = int8

type rune = int32 // byte和rune就是类型别名

3 类型定义和类型别名的区别

类型别名用=,结果还是原来类型,自定义类型不用=,结果是新定义的类型

4 结构体的定义

type 类型名 struct { 字段名 字段类型 字段名 字段类型 ... }

type Person struct {
    name string
    age int
}

5 结构体声明

var person Person

6 实例化

person.name = "gopher"

person.age = 18

7 匿名结构体

var p1 struct{Name string, Age int}

p1.Name = "erha"

p1.Age = 18

8 指针结构体

var p2 = new(Person)
P2.name = "gopher"
p2.age = 18
fmt.Printf("%T\n", p2)  // *main.	Person
fmt.Printf("p2=%#v\n", p2)  // p2=&main.Person{name:"gopher", age:18}

9 取结构体的地址实例化

var p3 = &Person{}
P2.name = "erha"
p2.age = 18

10 结构体初始化

没有初始化的结构体,其成员变量都是对应类型的零值

  • 使用键值初始化
p1 := Person {
   name: "gopher"
   age: 18
}
p1 := &Person {
   name: "gopher"
   age: 18
}
  • 使用值的列表初始化
p2 := &Person {
   "gopher"
   18
}

这种必须初始所有字段、顺序必须不能改变、不能和键值初始化混用

11 构造函数

Go结构体没有构造函数,可以自己实现

func newPerson(name string, age int8) *Person {
    return &person{
      name: name,
      age:  age,
    }
}

12 方法

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) { 函数体 }

//Study Person做梦的方法
func (p Person) Study() {
		fmt.Printf("%s Go \n", p.name)
}
func (p *Person) SetAge(newAge int8) {
		p.age = newAge
}
值类型接收者和指针类型接收者是有区别的

方法和函数的区别是,函数不属于任何类型,方法属于特定的类型

13 结构体的匿名字段

type Person struct {
    string
    int
}

14 嵌套结构体

//Address 地址结构体
type Address struct {
    Province string
    City     string
}

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address Address
}

15 嵌套匿名结构体

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address
}

16 结构体的"继承"

就是组合

type Animal struct {
		name string
}

type Dog struct {
    Feet    int8
    *Animal //通过嵌套匿名结构体实现继承
}

17 结构体标签

type Person struct {
    ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的key
    Name string //json序列化是默认使用字段名作为key
    age string //私有不能被json包访问
}

七、接口

1 接口类型

Go中接口是一种类型,一种抽象的类型

interface是一组method的集合,也就是一个需要实现的方法列表

2 接口的定义

type 接口类型名 interface {
		方法名1(参数列表1) 返回值列表1
		方法名2(参数列表2) 返回值列表2
}

3 实现接口的条件

一个对象只要全部实现了接口中的方法,就实现了这个接口

4 接口类型变量

type Writer interface {
    write()
}
var w Writer // 声明一个Writer类型的变量w

5 值接收者和指针接收者

就是看传入结构体类型是值类型 还是 指针类型

type Mover interface {
		move()
}

type dog struct {}

func (d dog) move() {
		fmt.Println("erha")
}

func main() {
    var x Mover
    var erha = dog{} // 二哈是dog类型
    x = erha         // x可以接收dog类型
    var za = &dog{}  // 藏獒是*dog类型
    x = za           // x可以接收*dog类型
    x.move()
}

func (d *dog) move() {
		fmt.Println("zaza")
}
func main() {
    var x Mover
    var erha = dog{} // 二哈是dog类型
    x = erha         // x不可以接收dog类型
    var za = &dog{}  // 藏獒是*dog类型
    x = za           // x可以接收*dog类型
}

6 接口嵌套

// Sayer 接口
type Sayer interface {
		say()
}

// Mover 接口
type Mover interface {
		move()
}

// 接口嵌套
type animal interface {
    Sayer
    Mover
}

7 空接口

空接口定义:var a interface{}

空接口的应用:

  1. 空接口作为函数的参数
  2. 空接口作为map的值

8 类型断言

var a interface{}
v, ok := a.(string)
......

断言后可以使用switch
如 switch v := x.(type) {
    case string:
    ......
    default:
    ......
}

八、并发

1 并发和并行

Erlang 之父 Joe Armstrong那张图:并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机,如果串行,一个队列使用一台咖啡机。并发和并行都可以是很多个线程,就看这些能不能同时被(多个)cpu执行,如果可以就说明是并行,而并发是多个线程被(一个)cpu轮流切换着执行。

2 goroutine

go并发使用goroutine(runtime)和channel

启动:go func() {...},启动多个用for循环

3 goroutine的调度

GPM是go运行时(runtime)层面的实现,是go自己实现的一套调度系统。

  • G就是个goroutine,里面除了存放goroutine信息外,还有与所在P的绑定信息

  • P管理着一组goroutine队列,P里面会存储当前goroutine运行的上下文环境,P对自己管理goroutine进行调度,自己的队列消费没了就去全局队列取,全局队列也没了就去其他P队列抢任务。

  • M是go运行时对操作系统内核线程的虚拟,与内核线程一般是一一映射的关系,goroutine最终要放到M上执行。P与M一般也是一一对应的,P管理着一组G挂载在M上运行,一个G长期阻塞在M上时,runtime会新建一个M,阻塞G所在的P会把其他的G挂载到新建的M上,旧的G阻塞完成时,回收旧的M。

goroutine是运行时go自己的调度器调度,不需要os内核来调度,不涉及用户态和内核态切换。

go运行的调度器使用GOMAXPROCS参数来确定需要使用多少个os线程来同时执行go代码,默认是cou核心数,可以通过runtime.GOMAXPROCS()设置当前程序并发占用的cpu核心数。

3 channel

Go提倡通过通信共享内存而不是通过共享内存而实现通信。

channel定义:var 变量 chan 元素类型,例如var c chan int

channel创建:make(chan 元素类型, [缓冲区大小]),例如

c := make(chan int)     // 无缓冲区
c := make(chan int, 1)  // 有缓冲区

channel操作:

  • 发送: c <- 222
  • 接收: v := <- c,www.jintianxuesha.com<-c(忽略结果)
  • 关闭:close(c)

单向通道

  • 只读通道 in <-chan int
  • 只写通道 out chan<- int

4 select(从多个channel接收数据)

// 性能会很差
for {
    // 从ch1接收值
    v, ok := <-ch1
    // 从ch2接收值
    v, ok := <-ch2
    …
}

select {
    case <www.yuntianyul.com-ch1:
    ...
    case v <- ch2:
    ...
    case v2 :www.chuancenpt.com= ch3:
    ...
    default:
    ...
}

如果多个case同时满足,select会随机选择一个;没有case的select会一直等待,用于阻塞main。

5 并发安全锁

互斥锁:sync.Mutex

读写互斥锁:sync.RWMutex

并发任务同步:sync,WaitGroup

wg *WaitGroup Add(www.feihongyul.cn),wg www.hongtuupt.cn *WaitGroup Done(),wg *WaitGroup Wait()

高并发任务只执行一次:sync.Once,只有一个Do方法,使用:

var one sync.Once
one.Do(func(www.yixingylzc.cn){www.jiuyueguojizc.cn   })

还可以用来实现单例。

6 原子操作

sync/atomic

九、反射

获取值的类型:reflect.TypeOf(www.baihua178.cn)

type定义的类型:x.Name(www.feishenbo.cn)

底层的类型:x.Kind(www.qiaoheibpt.com)

原始值:reflect.ValueOf(www.baishenjzc.cn)

结构体反射:x.NumField(www.yachengyl.cn) x.Field()

GoStudy基础小册

标签:全局   lag   next   rate   断言   main   容量   链表   group   

原文地址:https://www.cnblogs.com/woshixiaowang/p/13532737.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!