赞
踩
var n int8 n=100 fmt.Println(n) //100 没有问题 //如果赋值为200 则不行 因为int8取值范围最大是127
v1 := 'A' v2 := "A"
//单引号存储的是 ASCII编码 //A的ASCII值=65 //B的ASCII值B=66 //a的ASCII值a=97
fmt.Printf("v1的类型是%T,%d,值为%s\n", v1, v1) // int32 A 65
fmt.Printf("v2的类型是%T,%s\n", v2, v2) //string A
//字符串的长度 //中文占3个字节
fmt.Println(len(v2)) //1
//获取某个字节
s2 := `hello go`
fmt.Println(s2[0]) //104
双引号单引号如果作为字符串输出,需要使用\"
进行转义后才能使用 \n \r \t 为特殊作用字符。
//字符转义空格
fmt.Println("hello \t golang")//hello golang
//输出换行 \n
//回车符号 \r
//输出路径
fmt.Println("E:\\golang\\go.jpg")//E:\golang\go.jpg
//双引号
fmt.Println("hello \"golang\"") //hello "golang"
//布尔类型作为条件比较返回结果只有true和false两种
a:=10
fmt.Println(a==2) //false
fmt.Println(a!=2) //true
Go语言有两种精度的浮点数 float32 和 float64。浮点类型的数据取值范围可以从很小或者很巨大.
1.79E-308
是 1.79 乘以 10的负308次方。 1.79E+308
是 1.79 乘以 10的308次方。
- var a int8 = 10 var b int16 //b=a 因为类型不同不能直接转换
- b= int16(a) fmt.Println(a,b)//10,10f1:=3.12 var c int
- c = int(f1) fmt.Println(f1,c)// 3.12 , 3 浮点类型转为整形的时候 只是取了整数部分
- //不是所有类型都能互相转换 //数值类型的可以转换 int 和bool 不能转换
arr := [5]int{1,2,3,4,5}
//for循环
for i:=0; i
fmt.Println(arr[i])
}
break 用来终止执行for循环语句,终止整个循环。continue 终止当前循环的迭代,重新进入下一条件,进入循环。+
//语法
lable:func1
...
goto label
- package main
-
- import "fmt"
-
- func main() {
- values := []int{4, 3, 14, 85, 34, 27, 91, 95, 26,12,32}
- fmt.Println(values)
- BubblingASC(values)//正序冒泡
- BubblingDESC(values)//倒序冒泡
- }
-
- //冒泡排序 正序,大的靠后 小的靠前。
- func BubblingASC(values []int) {
- for i := 0; i < len(values)-1; i++ {
- for j := i+1; j < len(values); j++ {
- if values[i]>values[j]{ //左右两边数据对比
- values[i],values[j] = values[j],values[i] //数据交换
- }
- }
- }
- fmt.Println(values)
- }
-
- //冒泡排序 倒序, 大的靠前 小的靠后。
- func BubblingDESC(values []int) {
- for i := 0; i < len(values)-1; i++ {
- for j := i+1; j < len(values); j++ {
- if values[i]<values[j]{ //左右两边数据对比
- values[i],values[j] = values[j],values[i] //数据交换
- }
- }
- }
- fmt.Println(values)
- }
- package main
-
- import "fmt"
-
- func main() {
- a, b, c := myfunc()
- fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
- }
-
- func myfunc() (a, b, c int) {
- a, b, c = 111, 222, 333
- return
- }
切片也是一种存储相同类型的数据结构,但是不同于数组的是它的大小可以改变,如果长度不够可以自动扩充。
- //声明一个切片slice
- var slice []int
- //使用make函数创建切片
- s1:=make([]int,0,5)
- fmt.Println(s1)// [] 打印空的切片
- s1=append(s1,1,2)
- fmt.Println(s1)// [1,2]
- //因为切片可以扩容 所以定义容量为5 但是可以加无数个数值
- s1=append(s1,3,4,5,6,7)
- fmt.Println(s1)// [1,2,3,4,5,6,7]
- //添加一组切片到另一切片中
- s2:=make([]int,0,3)
- s2=append(s2,s1...) //...表示将另一个切片数组完整加入到当前切片中
make()是Go语言中的内置函数,主要用于创建并初始化slice切片类型,或者map字典类型,或者channel通道类型数据。他与new方法的区别是。new用于各种数据类型的内存分配,在Go语言中认为他返回的是一个指针。指向的是一个某种类型的零值。make 返回的是一个有着初始值的非零值。
- //测试使用new方法新建切片
- slice1 := new([]int)
- fmt.Println(slice1) //输出的是一个地址 &[]
-
- //使用make创建切片
- slice2 := make([]int, 5)
- fmt.Println(slice2)//输出初始值都为0的数组, [0 0 0 0 0]
-
- fmt.Println(slice1[0])//结果出错 slice1是一个空指针 invalid operation: slice1[0] (type *[]int does not support indexing)
- fmt.Println(slice2[0])//结果为 0 因为已经初始化了
- package main
-
- import (
- "fmt"
- )
-
- func main() {
- s1 := make([]int, 0, 3)
- fmt.Printf("地址%p,长度%d,容量%d\n", s1, len(s1), cap(s1))
- s1 = append(s1, 1, 2)
- fmt.Printf("地址%p,长度%d,容量%d\n", s1, len(s1), cap(s1))
- s1 = append(s1, 3, 4, 5)
- fmt.Printf("地址%p,长度%d,容量%d\n", s1, len(s1), cap(s1))
-
-
- //地址0xc000010540,长度0,容量3
- //地址0xc000010540,长度2,容量3
- //地址0xc00000e4b0,长度5,容量6
- //如果添加的数据容量够用, 地址则不变。
- //如果实现了扩容, 地址就会发生改变成新的地址,旧的则自动销毁。
- }
int、float、string、bool
array、slice、map、struct、pointer、function、chan
int、float、string、bool、array、struct
slice、pointer、map、chan
等都是引用类型。引用传递因为存储的是内存地址,所以传递的时候则传递是内存地址,所以会出现多个变量引用同一个内存。
- //数组为值传递类型
- //定义一个数组 arr1
- arr1 := [4]int{1, 2, 3, 4}
- arr2 := arr1 //将arr1的值赋给arr2
- fmt.Println(arr1, arr2) //[1 2 3 4] [1 2 3 4] 输出结果 arr1与arr2相同,
- arr1[2] = 200 //修改arr1中下标为2的值
- fmt.Println(arr1, arr2) //[1 2 200 4] [1 2 3 4] 结果arr1中结果改变,arr2中不影响
- //说明只是将arr1中的值给了arr2 修改arr1中的值后并不影响arr2的值
-
- //切片是引用类型
- //定义一个切片 slice1
- slice1 := []int{1, 2, 3, 4}
- slice2 := slice1 //将slice1的地址引用到slice2
- fmt.Println(slice2, slice2) //[1 2 3 4] [1 2 3 4] slice1输出结果 slice2输出指向slice1的结果,
- slice1[2] = 200 //修改slice1中下标为2的值
- fmt.Println(slice1, slice2) //[1 2 200 4] [1 2 200 4] 结果slice1中结果改变,因为修改的是同一份数据
- //说明只是将slice1中的值给了slice2 修改slice1中的值后引用地址用的是同一份 slice1 和slice2 同时修改
-
- fmt.Printf("%p,%p\n", slice1, slice2)//0xc000012520,0xc000012520
- //切片引用的底层数组是同一个 所以值为一个地址 是引用的底层数组的地址
- fmt.Printf("%p,%p\n", &slice1, &slice2)//0xc0000044a0,0xc0000044c0
- //切片本身的地址
深拷贝是指将值类型的数据进行拷贝的时候,拷贝的是数值本身,所以值类型的数据默认都是深拷贝。浅拷贝指的是拷贝的引用地址,修改拷贝过后的数据,原有的数据也被修改。 那么如何做到引用类型的深拷贝?也就是需要将引用类型的值进行拷贝。修改拷贝的值不会对原有的值造成影响。
- //使用range循环将切片slice中的元素一个一个拷贝到切片s2中
- slice := []int{1, 2, 3, 4}
- s2 := make([]int, 0)
- for _, v := range slice {
- s2 = append(s2, v)
- }
- fmt.Println(slice) //结果 [1 2 3 4]
- fmt.Println(s2) //结果 [1 2 3 4]
- //copy(目标切片,数据源) 深拷贝数据函数
- s2 := []int{1, 2, 3, 4}
- s3 := []int{7, 8, 9}
-
- copy(s2, s3) //将s3拷贝到s2中
- fmt.Println(s2) //结果 [7 8 9 4]
- fmt.Println(s3) //结果 [7 8 9]
-
- copy(s3, s2[2:]) //将s2中下标为2的位置 到结束的值 拷贝到s3中
- fmt.Println(s2) //结果 [1 2 3 4]
- fmt.Println(s3) //结果 [3 4 9]
-
- copy(s3, s2) //将s2拷贝到s3中
- fmt.Println(s2) //结果 [1 2 3 4]
- fmt.Println(s3) //结果 [1 2 3]
删除切片中元素的方法
- //方法一 获取切片指定位置的值 重新赋值给当前切片
- slice:=[]int{1,2,3,4}
- slice=slice[1:]//删除切片中开头1个元素 结果 [2,3,4]
-
- //方法二 使用append不会改变当前切片的内存地址
- slice = append(slice[:0], slice[1:]...) // 删除开头1个元素
- fmt.Println(slice)
删除指定的下标元素
- slice:=[]int{1,2,3,4}
- i := 2 // 要删除的下标为2
- slice = append(slice[:i], slice[i+1:]...) // 删除中间1个元素
- fmt.Println(slice) //结果[1 2 4]
删除切片结尾的方法
- slice := []int{1, 2, 3, 4}
- slice = slice[:len(slice)-2] // 删除最后2个元素
- fmt.Println(slice) //结果 [1,2]
- var m1 map[int]string //只是声明 nil
- var m2 = make(map[int]string) //创建
- m3 := map[string]int{"语文": 89, "数学": 23, "英语": 90}
-
- fmt.Println(m1 == nil) //true
- fmt.Println(m2 == nil) //false
- fmt.Println(m3 == nil) //false
-
- //map 为nil的时候不能使用 所以使用之前先判断是否为nil
- if m1 == nil {
- m1 = make(map[int]string)
- }
-
- //1存储键值对到map中 语法:map[key]=value
- m1[1]="小猪"
- m1[2]="小猫"
-
- //2获取map中的键值对 语法:map[key]
- val := m1[2]
- fmt.Println(val)
-
- //3判断key是否存在 语法:value,ok:=map[key]
- val, ok := m1[1]
- fmt.Println(val, ok) //结果返回两个值,一个是当前获取的key对应的val值。二是当前值否存在,会返回一个true或false。
-
- //4修改map 如果不存在则添加, 如果存在直接修改原有数据。
- m1[1] = "小狗"
-
- //5删除map中key对应的键值对数据 语法: delete(map, key)
- delete(m1, 1)
-
- //6 获取map中的总长度 len(map)
- fmt.Println(len(m1))
-
- //map的遍历
- 因为map是无序的 如果需要获取map中所有的键值对
- 可以使用 for range
- map1 := make(map[int]string)
- map1[1] = "张无忌"
- map1[2] = "张三丰"
- map1[3] = "常遇春"
- map1[4] = "胡青牛"
-
- //遍历map
- for key, val := range map1 {
- fmt.Println(key, val)
- }
- //创建一个map存储第一个人的信息
- map1 := make(map[string]string)
- map1["name"] = "张无忌"
- map1["sex"] = "男"
- map1["age"] = "21"
- map1["address"] = "明教"
-
- //如果需要存储第二个人的信息则需要重新创建map
- map2 := make(map[string]string)
- map2["name"] = "周芷若"
- map2["sex"] = "女"
- map2["age"] = "22"
- map2["address"] = "峨眉山"
-
- //将map存入切片 slice中
-
- s1 := make([]map[string]string, 0, 2)
- s1 = append(s1, map1)
- s1 = append(s1, map2)
-
- //遍历map
- for key, val := range s1 {
- fmt.Println(key, val)
- }
- package main
-
- import (
- "fmt"
- "sync"
- )
-
- //声明sync.Map
- var syncmap sync.Map
-
- func main() {
-
- //Store方法将键值对保存到sync.Map
- syncmap.Store("zhangsan", 97)
- syncmap.Store("lisi", 100)
- syncmap.Store("wangmazi", 200)
-
- // Load方法获取sync.Map 键所对应的值
- fmt.Println(syncmap.Load("lisi"))
-
- // Delete方法键删除对应的键值对
- syncmap.Delete("lisi")
-
- // Range遍历所有sync.Map中的键值对
- syncmap.Range(func(k, v interface{}) bool {
- fmt.Println(k, v)
- return true
- })
-
- }
包的概念就是我们程序中的目录,我们所写的所有代码都放在包中在定义的时候用package定义包, 然后使用 import 引入包。Go语言提供了很多内置包,例如:fmt、strings、strconv、os、io 等等。
- //是否包含指定的字符串中任意一个字符 有一个出现过 就返回true
- fmt.Println(strings.ContainsAny(s1,"glass"))
-
- //返回指定字符出现的次数
- fmt.Println(strings.Count(s1,"g"))
-
- //文本的开头
- fmt.Println(strings.HasPrefix(s1,"ok"))
- //文本的结尾
- fmt.Println(strings.HasSuffix(s1,".txt"))
-
- //查找指定字符在字符串中存在的位置 如果不存在返回-1
- fmt.Println(strings.Index(s1,"g"))
- //查找字符中任意一个字符出现在字符串中的位置
- fmt.Println(strings.IndexAny(s1,"s"))
- //查找指定字符出现在字符串中最后一个的位置
- fmt.Println(strings.LastIndex(s1,"s"))
-
- //字符串的拼接
- s2:=[]string{"123n","abc","ss"}
- s3:=strings.Join(s2,"_")
- fmt.Println(s3)// 123n_abc_ss
-
- //字符串的切割
- s4:=strings.Split(s3,"_")
- fmt.Println(s4)// 返回切片[]string{"123n","abc","ss"}
-
- //字符串的替换
- s5 := "okoletsgo"
- s6 := strings.Replace(s5, "o", "*", 1)
- fmt.Println(s6)//*koletsgo
- //TODO 1 只替换1次, -1 全部替换
-
- //字符串的截取
- //str[start:end]包含start 不包含end
主要用于字符串和基本类型的数据类型的转换
- /str:="aa"+100
- //字符串和整形数据不能放在一起 所以需要将100 整形转为字符串类型
- //+号在字符串中表示字符串的连接 在整形中表示数据的计算
-
- //string 转 bool类型
- s1 := "true" //字符串
- b, err := strconv.ParseBool(s1)
- if err != nil {
- fmt.Println(err) //打印错误信息
- }
- fmt.Printf("%T,%t", b, b) //bool,true
-
- //string 转int
- s1 := "100" //字符串
- b, err := strconv.ParseInt(s1, 10, 64)
- //10 表示s1要转的数据是10进制 64位
- if err != nil {
- fmt.Println(err) //打印错误信息
- }
- fmt.Printf("%T,%d", b, b) //int64,100
-
- //整形转为字符串
- s := strconv.Itoa(23)
- //字符串转为整形
- i, e := strconv.Atoi(s)
time包操作的都是时间,时间的单位都包括年,月,日,时,分,秒,毫秒,微妙,纳秒,皮秒。
- package main
-
- import (
- "fmt"
- "time"
- )
-
- func main() {
- //获取当前时间
- t := time.Now()
- fmt.Println(t) //2020-03-31 21:26:01.7307507 +0800 CST m=+0.001999001
- //获取的时间后面的信息是时区
-
- //上面的时间看起来不是很方便 于是需要格式化时间
- s := t.Format("2006年1月2日 15:04:05")
- fmt.Println(s)
- }
需要注意的是Go语言中时间的格式化,需要指定格式化时间的模板, 不管年月日的类型格式怎么写,但是具体的数值必须写成2006-01-02 15:04:05
, 如果不是这个日期就不能够格式化,这个时间也是为了纪念Go语言诞生的时间。
- s := t.Format("2006-1-2 15:04:05")
- fmt.Println(s) //打印出的格式就是当前的时间 2020-3-31 23:08:35
-
- s := t.Format("2006/1/2")
- fmt.Println(s) //打印出的格式就是当前的年月日 2020/3/31
-
- //字符串类型的时间
- str := "2020年3月31日"
- //第一个参数是模板,第二个是要转换的时间字符串
- s, _ := time.Parse("2006年1月2日", str)
- fmt.Println(s) //打印出的格式就是2020-03-31 00:00:00 +0000 UTC
-
- //获取年月日信息
- year, month, day := time.Now().Date()
- fmt.Println(year, month, day) //2020 March 31
-
- //获取时分秒信息
- hour, minute, second := time.Now().Clock()
- fmt.Println(hour, minute, second) //23 23 54
-
- //获取今年过了多少天了
- tday := time.Now().YearDay()
- fmt.Println(tday) //91 (今年已经过了91天了)
-
- //获取今天是星期几
- weekday := time.Now().Weekday()
- fmt.Println(weekday) //Tuesday
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总毫秒数。它主要是为用户提供一份电子证据.
- package main
-
- import (
- "fmt"
- "time"
- )
-
- func main() {
- //获取指定日期的时间戳
- t := time.Date(2020, 3, 31, 23, 30, 0, 0, time.UTC)
- timestamp := t.Unix()
- fmt.Println(timestamp) //1585697400
-
- //获取当前时间的时间戳
- timestamp2 := time.Now().Unix()
- fmt.Println(timestamp2) //1585669151
-
- //当前时间的以纳秒为单位的时间戳
- timestamp3 := time.Now().UnixNano()
- fmt.Println(timestamp3) //1585669151296330900
- }
-
-
-
- //时间间隔 相加
- now := time.Now()
- //当前时间加上一分钟
- t := now.Add(time.Minute)
- fmt.Println(now) //2020-03-31 23:43:35.0004791 +0800 CST m=+0.002999201
- fmt.Println(t) //2020-03-31 23:44:35.0004791 +0800 CST m=+60.002999201
-
- //计算两个时间的间隔
- d := t.Sub(now)
- fmt.Println(d) //1m0s 相差一分钟
- //将指定时间转为时间戳格式
- beforetime := "2020-04-08 00:00:00" //待转化为时间戳的字符串
- timeLayout := "2006-01-02 15:04:05" //转化所需模板
- loc := time.Now().Location() //获取时区
- theTime, _ := time.ParseInLocation(timeLayout, beforetime, loc) //使用模板在对应时区转化为time.time类型
- aftertime := theTime.Unix() //转化为时间戳 类型是int64
- fmt.Println(theTime) //打印输出theTime 2020-04-08 00:00:00 +0800 CST
- fmt.Println(aftertime) //打印输出时间戳 1586275200
-
- //再将时间戳转换为日期
- dataTimeStr := time.Unix(aftertime, 0).Format(timeLayout) //设置时间戳 使用模板格式化为日期字符串
- fmt.Println(dataTimeStr)
但是早期的Go语言被很多开发者所诟病的一个问题是依赖包的管理,在Golang1.5版本之前需要设置GOPATH来解决所有包依赖的问题,但是这样会有很多问题,如果我们两个项目引用的包版本不一致,而GOPATH中只有一个版本,就需要使用多个GOPATH来解决这样的问题,这样来回切换GOPATH是很不方便的。于是Go在1.9之后加入包管理方案解除了GOPATH的依赖。于是出现了dep
和glide
在项目中加入了vender
目录来存储所有项目中需要引入的包。
安装dep
MacOS brew install dep
Linux curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
Windows go get -u github.com/golang/dep/cmd/dep
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64adf95bb54a40d89466c37751be51a2~tplv-k3u1fbpfcp-zoom-1.image)
使用 dep status
查看项目依赖的详细信息和状态。
dep ensure
查看所有的依赖库都已经安装,如果没有就去下载。 dep ensure add github.com/go-sql-driver/mysql
下载添加新的依赖库,并增量更新清单文件和校验描述文件。 dep不是每次都去下载,他会先在本地环境中找如果没有找到则会到网上下载并添加到本地仓库。
使用mod需要注意的是:
GOPROXY=https://goproxy.io
这样没有梯子的情况下可以正确的加载相应的包文件。GO111MODULE
不要设置,如果已经增加了这个变量请务必设置为GO111MODULE=auto
。go mod init projectName
。执行上面的命令之后,就已经可以开发编译运行此项目了。他已经自动引用了项目中所有的包文件。
1,大写首字母函数共用,小写私用
定义一个匿名函数直接加上()就相当于直接调用了,通常只能调用一次,可以将匿名函数赋值给一个变量,这个变量就代表了这个函数。则可以调用多次。
匿名函数可以作为另一个函数的返回值
package main import ( "fmt" ) func main() { res2 := oper(20, 12, add) fmt.Println(res2)
- //匿名函数作为回调函数直接写入参数中
- res3 := oper(2, 4, func(a, b int) int {
- return a + b
- })
- fmt.Println(res3)
} func add(a, b int) int { return a + b } func reduce(a, b int) int { return a - b } //oper就叫做高阶函数 //fun 函数作为参数传递则fun在这里叫做回调函数 func oper(a, b int, fun func(int, int) int) int { fmt.Println(a, b, fun) //20 12 0x49a810A 第三个打印的是传入的函数体内存地址 res := fun(a, b)//fun 在这里作为回调函数 程序执行到此之后才完成调用 return res }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。