【VScode F5默认调试】

文件->打开文件夹 (选择该文件夹)

运行->添加配置,选GO,此时会在文件夹下建立一个.vscode文件夹,里面有个launch.json文件

在vscode里面打开launch.json文件,删除configurations下的配置,点右下角“添加配置”,选Go:launch file。切回.go文件,F5,完成

 

【sql语句过长换行】

stmtOut, err = dbConn.Prepare("这里写sql语句")
stmtOut, err := dbConn.Prepare(`这里
写sql
语句`)

  

 

【跨平台编译】

build

env GOOS=linux GOARCH=amd64 go build

 

【编译】

install

常用于本地打包编译的命令:go install

$GOPATH下文件夹go install

$GOPATH外单文件go install 文件名

打包之后在$GOPATH/bin下

 

【打印】

fmt.println(变量名),会换行

fmt.printf("%d",变量名),不会换行

有关fmt包的printf占位符 https://www.cnblogs.com/xiao-xue-di/p/11521823.html

 

 

【定义变量】

下划线变量

_ = append(s1, 6) 

如果有声明了不想用又不得不用的变量可以赋值给它,这个特殊变量不可读取。

 

 

var s int = 42(可读性最强,用于重要变量)
var s = 42     (介于两者之间)
s := 42          (最方便,用于很随意的变量)

多个变量一起声明

var(

  a = "123"

  b = "456"

 

 

其中for语句里面不能用var声明,直接用 := 就好

for i:=0; i<10; i++ {

}

 

 

如果定义一个变量不赋值,那么默认会赋予一个[零值]

  string类型的[零值]是一个空字符串,长度为0

  int类型的[零值]是0

  bool类型的零值]是false

    指针类型的[零值]是nil

 

 

 全局变量:

  首字母大写 - 外部全局变量

  首字母小写 - 内部全局变量

  内部全局变量只有当前包的代码可以访问

 

 

常量分全局常量和局部常量,常量必须初始化并赋值,不可二次赋值

 

 

指针变量和取地址符

取指针值*存在两次内存读写,第一次读取变量地址,第二次到这个地址取值

 

 

 

 

【条件语句】

循环for range,没有while,可用for{}(不写条件)代替

分支if swtich

条件都不需要加括号



 【数组】

数组的声明

var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var b [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
c := [8]int{1, 2, 3, 4, 5, 6, 7, 8}

  

声明之后,不可改变类型,不可改变长度

同类型&同长度数组之间才可以相互赋值

数组之间赋值之后修改任意一个数组元素的值,另一个数组相对应下标的值不会随之改变

 

 

 

 

 

 

【切片】

 

切片的创建

//创建一个容量cap为8,长度len为5的零值切片,值为[0 0 0 0 0]
var s1 []int = make([]int, 5, 8)

//创建一个容量和长度都为8的零值切片,值为[0 0 0 0 0 0 0 0]
var s2 []int = make([]int, 8) 

//也可以这样创建零值切片,参数从左到右依次是类型,Len,cap
var s1 = make([]int, 5, 8)
s2 := make([]int, 8)

//这样创建的切片是满容的
var s []int = []int{1,2,3,4,5}  // cap和len都为5

//创建空切片,他们值均为[] cap为0 len也为0
var s1 []int                    
var s2 []int = []int{}
var s3 []int = make([]int, 0)                    

切片之间直接赋值之后,修改其中一个切片的元素的值,另一个切片相对应元素的值会随之改变

切片之间用copy()赋值后,修改其中一个切片元素的值,另一个切片相对应元素的值不会发生改变

 

 切片的基础操作

package main

func main() {
	var s1 []int
	s2 := []int{14,15}
	for i := 0; i < 10; i++ {
		s1 = append(s1, i)
	}

	// 添加一个元素元素
	s1 = append(s1, 10)

	// 添加多个元素元素
	s1 = append(s1, 11, 12, 13)

	// 添加另一个切片的元素(后面加…)
	s1 = append(s1, s2...)

	// 删除索引最小的元素
	_ = s1[1:]

	// 删除索引最大的元素
	_ = s1[:1]

	// 删除 (非最大最小 && 索引为index)的元素
	index := 4
	_ = append(s1[:index], s1[index+1:]...)
}

  

 

切片append之后必须使用,切片append追加之后如果超出了原切片的容量,会变成一个新的切片,不再和原切片共享同一个底层数组,原切片改变元素新切片对应元素不变。

切片的扩容要用append,不能用赋值的方法扩容,否则会触发panic中断程序

func main() {
	var s1 []int
	s1[0] = 1	// 此处会触发panic
}

  

  当比较短的切片扩容时,系统会多分配 100% 的空间
  但切片长度超过1024时,扩容策略调整为多分配 25% 的空间

 

 

切片之后再切片

 

 

package main

import (
    "fmt"
)

func main() {
    a := [5]int{1, 2, 3, 4, 5}
    s := a[1:3] // s := a[low:high]
    //s:[2 3]
    fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
    s2 := s[3:4] // 索引的上限是cap(s)而不是len(s)
    fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
}

输出

s:[2 3] len(s):2 cap(s):4
s2:[5] len(s2):1 cap(s2):1

 

第一次对切片执行切片表达式时

a:[1,2,3,4,5]    

s:[2,3]             //a[1:3] 取切片 a 的索引 1 到 2 (a[1],a[2])得出 [2,3],实际容量为从a的索引1开始一直到最后,也就是容量为4

 

当对切片再次执行切片表达式时

s2[5]    //此时又把切片a拿出来,只不过此时的索引是从被s切过的地方算起,也就是[2,3,4,5] 。对[2,3,4,5]执行切片表达式[3:4]就是取第4个元素,值为5

 

 

【字典】有点类似于PHP的key->value数组

 

创建字典,使用 make 函数创建的字典是空的,长度为零,内部没有任何元素。

var m map[int]string = make(map[int]string)

 

字典初始化赋值

var m = map[int]string{
    90: "优秀",
    80: "良好",
    60: "及格",
}

  

字典检查Key是否存在

var score, ok = fruits["durin"]
if ok {
    fmt.Println(score)
} else {
    fmt.Println("durin not exists")
}

  

 

【字符串】

对中文字符串通过下标按字节遍历

package main

import "fmt"

func main() {
    var s = "嘻哈china"
    for i:=0;i<len(s);i++ {
        fmt.Printf("%v ", s[i])
    }
}

结果

229 152 187 229 147 136 99 104 105 110 97 

 

对字符串通过rune遍历

package main

import (
    "fmt"
)

func main() {
    v6 := []rune("嘻哈china")
    for k, v := range v6 {
        fmt.Printf("%c", v)
    }
}        

结果

//%c,该值对应的unicode码
嘻哈china        

//%v,该值的十进制表示
22075 21704 99 104 105 110 97

字符串不可按下标赋值,编译器会直接在语法上拒绝

 

字符串切割

func main() {
    var s1 = "hello world"
    var s2 = s1[3:8]  //s2类型依然是string
    fmt.Println(s2)
}
------------------------
lo wo

 

字符串和字节切片相互转换

var b = []byte(s1) // 字符串转字节切片
var s2 = string(b) // 字节切片转字符串

 

 

【结构体】

 创建

package main

import "fmt"

type Circle struct {
    x int
    y int
    Radius int
}

func main() {
    var c Circle = Circle {
        x: 100,
        y: 100,
        Radius: 50,  // 注意这里的逗号不能少
    }
    fmt.Printf("%+v\n", c)//%+v输出结构体时会加字段名
}

----------
{x:100 y:100 Radius:50}

  

如果赋值的时候缺省了,则用该类型[零值]代替

var c1 Circle = Circle {
    Radius: 50,
}

-----------------
{x:0 y:0 Radius:50}

 

还可以这样赋值

var c Circle = Circle {100, 100, 50}

但要所有的字段都赋值不能缺

 

使用new返回的是指针,同时所有字段均为[零值]

var c *Circle = new(Circle)

 

三种零值结构体初始化方法:

var c1 Circle = Circle{}
var c2 Circle
var c3 *Circle = new(Circle)

  

值类型的结构体之间的拷贝是不共享底层数据的
指针类型的结构体之间的拷贝是共享底层数据的

 

Go 语言的方法名称也分首字母大小写,它的权限规则和字段一样,首字母大写就是公开方法,首字母小写就是内部方法,只能归属于同一个包的代码才可以访问内部方法

 

结构体方法使用

func (c Circle) expandByValue() int {
  return c.Radius//go里,函数里要return的地方必须声明返回变量类型,也就是上面那个int
}

//调用
c.expandByValue()
---------------------------------------------
func  expandByPointer(c Circle) int{
  return c.Radius
}

//调用
expandByPointer(c)

 

结构体的 指针方法 和 值方法 的区别

package main

import "fmt"

type Circle struct {
	Radius int
}

func (c Circle) expandbyvalue() {
	c.Radius *= 2
}

func (c *Circle) expandbypoint() {
	c.Radius *= 2
}

func main() {
	var c = Circle{Radius: 50}
	c.expandbyvalue()
	fmt.Println(c.Radius)
	// 指针变量调用方法形式上是一样的
	var pc = &c
	pc.expandbypoint()
	fmt.Println(pc.Radius)
}

------------------------------------------
50
100

通过指针访问内部的字段需要 2 次内存读取操作,第一步是取得指针地址,第二部是读取地址的内容。结构体进行值拷贝时,如果结构体很大,那拷贝的就很慢,如果此时就拷贝个指针,就很快

 

内嵌结构体

type Point struct {
    x int
    y int
}

func (p Point) show() {
    ...
}


type Circle struct {
    loc Point
    Radius int
}

func main() {
    var c = Circle {
        loc: Point {
            x: 100,
            y: 100,
        },
        Radius: 50,
    }
    
    //结构体
    fmt.Printf("%+v\n", c)

    //内嵌结构体
    fmt.Printf("%+v\n", c.loc)

    //内嵌结构体的变量
    fmt.Printf("%d %d\n", c.loc.x, c.loc.y)

    //内嵌结构体的方法
    c.loc.show()
}

匿名内嵌结构体

type Point struct {
    x int
    y int
}

func (p Point) show() {
    ...
}


type Circle struct {
    Point     // 匿名内嵌结构体
    Radius int
}

func main() {
    var c = Circle {
        Point: Point {
            x: 100,
            y: 100,
        },
        Radius: 50,
    }
    
    fmt.Printf("%+v\n", c)
    fmt.Printf("%+v\n", c.Point)
    fmt.Printf("%d %d\n", c.x, c.y) // 继承了字段
    fmt.Printf("%d %d\n", c.Point.x, c.Point.y)
    c.show() // 继承了方法
    c.Point.show()
}

  

多态:子类可以重新定义父类的方法

GO语言结构体不支持多态

 

 

【defer 和 return 】

func c() (i int) {
    defer func() 
    return 1
}
    

defer 会延迟执行函数,但会在他所在的函数销毁之前被执行

先defer的后执行,后defer的先执行

参考来源 https://www.cnblogs.com/ricklz/p/9574645.html

 

【map】

多协程并发操作下用sync.Map,单协程下用 map

在并发下操作 map 可能会panic报错,fatal error: concurrent map writes

 

定义map

make(map[KeyType]ValueType, [cap])
// 例:
scoreMap := make(map[string]int, 8)

 

添加元素

scoreMap["张三"] = 90

 

判断某个键是否存在

v, ok := scoreMap["张三"]
if ok {
  fmt.Println(v)
} else {
  fmt.Println("查无此人")
}

  

遍历map

for k, v := range scoreMap {
  fmt.Println(k, v)
}

 

删除键值对

 scoreMap := make(map[string]int)
 scoreMap["小明"] = 100
 delete(scoreMap, "小明")	// 将小明:100从map中删除

 

【sync.Map】

需要保证线程安全且读多写少的情况下用sync.Map,此方法在性能上存在一些问题,如果是大量并发的Read,则问题不明显

package main

import (
	"fmt"
	"sync"
)

var sm = new(sync.Map) // var sm *sync.Map = new(sync.Map)

func main() {
	// store 方法,添加元素
	sm.Store(1, "a")

	// Load 方法,获得value
	if v, ok := sm.Load(1); ok {
		fmt.Println(v)
	}

	// Delete 方法,删除元素
	sm.Delete(1)

	// 遍历该map,参数是个函数,该函数参的两个参数是遍历获得的key和value,返回一个bool值,当返回false时,遍历立刻结束。
	sm.Range(func(k, v interface{}) bool {
		fmt.Print(k)
		fmt.Print(":")
		fmt.Print(v)
		fmt.Println()
		return true
	})

	fmt.Println(sm.Load(1))
}

  

 

【接口 interface】

空接口的应用,一般遇到不确定参数类型的地方就用空接口

// 定义一个空接口x
var x interface{}

// 字符串string

s := "Hello 沙河"
x = s
fmt.Printf("type:%T value:%v\n", x, x)

// int
i := 100
x = i
fmt.Printf("type:%T value:%v\n", x, x)

// bool
b := true
x = b
fmt.Printf("type:%T value:%v\n", x, x)

 

空接口作为函数参数

func show(a interface{}) {
  fmt.Printf("type:%T value:%v\n", a, a)
}

 

空接口作为map值

var studentInfo = make(map[string]interface{})
studentInfo["name"] = "沙河娜扎"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo)

  

类型转换

func test(a interface{}) int {
  return a.(int)
}

  

posted on 2020-03-31 12:23  longzhankunlun  阅读(232)  评论(0)    收藏  举报