golang 学习笔记

Golang学习笔记,建议有编程基础的观看
中间的代码有些大小写有一点问题
建议在使用时候记得公用函数调用需要大写

输出的区别

Print printf println
Fmt.println 自动换行

Fmt.printf 是格式化输出

%T 可以输出变量类型

fmt.Printf(“a= %v a的类型是%T”,a,a)

输出: a=10 a的类型是int

%v原样输出
%d表示10进制输出 // %02d 两位常数,不够补0
%b表示二进制输出
%o表示八进制输出
%x表示16进制输出
%f 表示浮点型输出 默认保留6位小数 %.4f保留四位小数
%t 表示bool类型

字符串转义符
\n换行
\r\n 文件中的换行
\是特殊的 要转义输出\需要使用\ 输出反斜杠

输入

fmt.Println("请输入一个整数,一个浮点类型:")
fmt.Scanln(&x,&y)//读取键盘的输入,通过操作地址,赋值给x和y   阻塞式
fmt.Printf("x的数值:%d,y的数值:%f\n",x,y)
​
fmt.Scanf("%d,%f",&x,&y)
fmt.Printf("x:%d,y:%f\n",x,y)

变量

变量的定义

Go 语言中定义的类型是啥,赋值就是这种类型,否则会报错。

单个变量的定义
全局变量

Var 变量名 类型 = 表达式

var a int = 10

Var 变量名 类型

var a int
a = 10

短变量

变量名 := 表达式

a := 10

短变量声明法
在函数内部可以使用更简略的 := 方式声明并初始化变量
注意:短变量只能用于声明局部变量,不能用于全局变量的声明

变量名 := 表达式

a := 10

a,b,c := 12,13,"c"

匿名变量

func getuserinfo()(string,int){
return “zhangsan”,10
}

正常:

var username,age = getuserinfo()

匿名:

var username, _ = getuserinfo()

一次性定义多个变量

var 变量名称 ,变量名称 类型
Var a1 , a2 string

Var (
变量名称 类型
变量名称 类型
)

var(
Username string
Age int 
Sex string
)

常量的定义

定义的时候必须赋值,不能改变常量的值

单个常量定义

Const pi string = “常量”

多个常量的定义

const (
N1 = 100
N2 = 200
N3 =300
)

当定义多个变量,后边的值省略,未定义的后边的值默认与前边相同

const (
N1 =100
N2
N3
)

Iota计数器
const结合lota使用 iota每次在const使用时都为0
再次使用则值++

const(
N1 = iota
N2 = iota
N3 = iota
)

结果输出为: N1 = 0 N2= 1 N3 =2

iota在const中进行插队

const(
N1 = iota //0
N2 = 100 //100
N3 = iota //2
N4     //3
)

多个iota定义在一行,

const(
N1,N2 = iota+1, iota+2 //1 2  iota=0
N3,n4			  //2 3	iota=1 n3=iota+1 n4=iota+2
N5,n6			  //3 4	iota=2 
)

数据类型

整型的不同类型
默认值0

在这里插入图片描述

unsafe.Sizeof()

可以通过这个函数查看不同长度的整型 在内存里边的存储空间

浮点数类型
支持float32 和float64
Float32浮点数的最大范围是3.4e38 可以使用常量定义:math.maxfloat32
Float64浮点数的最大范围是1.8e308 可以使用常量定义:math.maxfloat64

2e-2 = 2/10^2

布尔类型
Bool 只有ture和false两种值 默认值是false

string类型
默认值是空 “”

字符串的常用操作
在这里插入图片描述

想一次定义多行字符串

 Str := `this is str
this is str
this is str
this is str
`

求字符串的长度
Len(字符串变量名)

一个汉字占3个字节

拼接字符串

Fmt.println(str1+str2)

Fmt.sprintf(%v %v”,str1,str2)

拆分字符串 插入

var str1 =123-456-789”
Arr :=fmt.Split(str1,-)  //以-分割字符串 Arr= [123 456 789]
Str2 := strings.Join(arr,(*))  //[123*456*789]

Str[2,5]指截取字符串中的2-5 在str1中是3-4

var str = []string{ "flower","flow","flight"}
fmt.Println(str)
fmt.Println(str[0])
fmt.Println(str[0][3:5])

输出
[flower flow flight]
flower
we

查找字符串
Strings.index() 从前往后查找
Strings.lastindex() 从后往前查找
查找不到返回-1 从0开始

Golang中使用的是utf-8编码 是int32

修改字符串 rune类型和byte类型

S1 := “big”
Bytestr := []byte(s1)
Bytestr[0] = 'p'
fmt.println(string(bytestr))

输出 pig

S1 := “你好big”
Runestr := []rune(s1)
Runestr[0] = ‘大’
fmt.Println(string(Runestr))

输出 大好big

数组与切片

Var arr1 [3]int
Var arr1 = [3]int{1,2,3}
Var arr =[...]int{0:1 , 1:10 , 2:20 , 5:40}		 //此数组长度为6 arr[0]=1 

arr[1]=10 arr[2]=20 arr[3]=0 arr[4]=0 arr[5]=40

Len(数组) //输出数组长度

基本数据类型 和 数组都是值类型 改变变量副本值时不会改变变量本身的值
引用数据类型 改变变量副本值时会改变变量本身的值

切片的定义:var arr1 []T

Nil 默认零值 (切片的默认值)

Cap()容量

用make函数构造切片

make([]int, 4 ,8) 		//创建一个切片,长度是4 容量是8

不能通过下标的方式扩容 扩容要使用append()

Arr1 = Append(arr1, 12)		//往切片后边进扩容 多加一个12
Arr1 = Append(arr1, arr2)		//切片的合并

合并切片时最后一个元素要加…

Append(arr1[:3],arr1[5:]...)

切片的扩容策略:
每次扩容都是上次的两倍 2 2^2 2^3 2^4

使用copy()函数复制切片 复制的切片是引用数据类型

Copy(a,b)		//把b复制到a中

排序算法:
冒泡升序
Sort.ints()
Sort.float64s()
逆序(降序):
Intlist是切片
Sort.sort(sort.reverse( sort.intslice( intlist )))

Map类型

Map的存放是随机的

Map的创建

var maptest = make(map[string]string)
Maptest[“username”] = “张三”
Maptest[“age”] =20”
Maptest[“sex”] = “男”

或者

Var maptest = make(map[string]string){
“username”:”张三”
}	
Maptest := map[string]string{
“username”:”张三”
}

查找key
Maptest[“username”] 返回两个值一个value,一个bool

Make([]map[string]string,3,3)分配空间不赋值,默认为nil
长度是3,一共有3个

类型转换
最好把低类型转换为高类型

1.fmt.printf进行转化为string
2.Strconv 把其他类型转化为int类型

Strconv.formatint()

Strconv.formatfloat()
参数1:要转化的值
参数2:格式化类型
‘f’(-ddd.dddd)
‘b’(-ddddp±dd,二进制指数)
参数3:保留的小数点
参数4:格式化的类型 传入 64 32
Strconv.formatbool() //把bool转化为string

3.字符串转化为数字
Str := “123456”
Fmt.printf(“%v–%t\n”,str,str)
Num,_ :=strconv.parseint(str,10,64)

注意strconv.parseint(str,10,64)函数返回两个值 int 和 bool

数字转化为字符串
string:=strconv.Itoa(int)

结构体Struct

结构体是值类型

自定义类型
Type 自定义名 类型 //(可以是函数)如func(int, int) int

类型别名
Type 自定义名 = 类型

结构体
type 类型名 struct{
字段名 字段类型
字段名 字段类型
……
}
当类型名(/字段名)的首字母大写时表示这个类型是公有的,如果是小写时表示这个类型是私有的

实例化(分配空间)
Var 变量名 结构体类型

可以通过new关键字
Var p2 = new(类型名) p2是个结构体指针

Var p3 = &类型名{} //p3是个结构体指针 {}中可以进行赋值初始化 key可以不写

通过键值对来实例化
Var p4 = { //p4也是结构体指针
字段名: 值,
字段名:值,
……
}

结构体里的方法
结构体名为person
方法为:
Func (p person) printinfo(){
Fmt.priintf(“姓名%v, 年龄%v”, p.name,p.age)
}

调用时 p1. printinfo()
如果要修改结构体里的值 则需要使用指针
Func (p *person) printinfo(name string){
Fmt.priintf(“姓名%v, 年龄%v”, p.name,p.age)
P.name = name
}

匿名结构体
type 类型名 struct{
字段类型
字段类型 //匿名的结构体 字段类型不能重复
……
}

嵌套结构体(继承)
type 类型名 struct{
字段名 字段类型
字段名 字段类型
字段名 结构体名
字段名 切片/map
……
}

语法

for循环
没有while循环

S:=”你好 golang”
for _,v:= range s{
fmt.printf(%v(%c),v,v)
}

For i:= 1 ; i <= 10 ; i++{
执行语句
}
I := 1
For i<=10{
I++
}

无限循环
For {
执行语句
}

For range

var str = “你好golang”
for k, v:=range str{
fmt.Orintf(“key= %v,value=%c\n”,k,v)
}

运算符

      • /
        除法运算的数都是整数时,最后的结果会只保留整数部分

取余注意: 余数=被除数-(被除数/除数)*除数
-10%3 = -10-(-10/3)*3

Golang中i++ ++ – 是单独的运算符,不能给变量赋值,他只能单独使用
错误写法:a = i++
++ – 只能后置 不能前置
错误写法:++i

== != > < <= >=
&& || ! 逻辑not运算符,如果条件为 ture 则为false 否则为ture

赋值运算符 += -= /= *= %=

& 二进制 两个均为1才为1
| 两位有一个1就为1
^ 异或 两位不一样则为1
<<左移n位 乘以2的n次方

右移除以2的n次方
If
{必须紧挨着条件

If 条件 {
执行语句
}
Else if 条件{
执行语句
}
Else{
执行语句
}

If age:=34 ; age>20{ //age局部变量

}

Switch选择

Switch 变量{
Case 条件: //条件可以是表达式(switch后面不用加变量),也可以是值
Default:
}
Golang中break可以写可以不写
一个case可以有多个值
Case 1,3,5,7,9: //判断奇数
Fallthrough穿透关键词,继续执行下一个case 只作用下一个语句

跳出语句
Break continue

Lable:
For {
For{
Break lable //跳出到lable
}
}

Goto

直接跳到指定的位置执行
Goto lable

Lable :

select

select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case /
default : /
可选 */
statement(s);
}
函数的定义
Func 函数名(参数 参数类型,参数 参数类型)返回值类型{
函数体
}
参数可以写成可变参数(可变参数只能放到参数列表后面): 求参数和
func sumfn1(x… int )int{
Sum := 0
For _,v := range x {
Sum +=v
}
Return sum
}

返回多个值

Func 函数名(参数 参数类型,参数 参数类型)(返回值类型,返回值类型){
函数体
Return 返回值,返回值
}

或者
Func 函数名(参数 参数类型,参数 参数类型)(变量名 返回值类型,变量名 返回值类型){
函数体
Return
}

自定义类型

自定义函数类型
Type calc 函数名(参数类型,参数类型 )返回值类型{

}
自定义类型
Type myint int
把函数作为参数
Func add(x,y int )int {
Return x + y
}
Func sub(x,y int )int {
Return x - y
}
Type calctype func (int, int) int //自定义一个方法类型
Func calc(x,y int,cb calctype) int {
Return cb(x , y)
}

匿名方法
在函数体中定义 func(x,y int )int {
Return xy
}
匿名自执行函数:
func(x,y int )int {
Return x
y
}(参数,参数 )

闭包

可以让一个变量常驻内存并且不污染全局
函数里边嵌套一个函数 最后返回里面的函数就是闭包
闭包=函数+引用环境

func c() func(int) int {
    var x int
    return func(a int) int {
        x++
        return a + x
    }
}

func main() {
    A := c()
    fmt.Println("x:", A(1))
    fmt.Println("x:", A(2))
}

输出 x:2
x:4
Defer
延迟执行代码
Defer注册要延迟执行的函数时,该函数的所有参数都要确定其值

panic/recover

用来处理错误,panic可以在任何地方触发,但recover只有在defer调用的函数中有效
recover捕获Panic()
程序碰到Panic()结束执行
在这里插入图片描述

Time包

日期
2006表示年
01 月
02日
03 时 //写为15表示24小时制
04分
05秒

time.Now()	//获取当前时间
time.Now().Year()	//获取当前年份
time.Now().Format(2006-01-02 030405)	//格式化
time.Now().Unix()	//获取当前时间戳 us毫秒
time.Now().UnixNano()	//获取当前时间戳 ns纳秒

把时间戳换成日期字符串:

timeobj := time.now().Unix(int64)时间戳 , 0)
var Str = timeobj.Format(2006-01-02 030405)	//格式化

str为符合格式的日期字符串

日期字符串转化为时间戳:
Var str = “2020-9-2 19:30:30” //日期字符串
Var tmp = “2006-01-02 03:04:05” //格式
Timeobj := time.parseinlocation(tmp,str,time.local) //将符合格式的日期字符串转化为时间
Timeobj.now().unix()

定时器

Ticker := Time.newticker(time.second) //每隔一秒执行一次
For t := range ticker.c{
Fmt.println(t)
}

休眠一秒钟:
Time.Sleep(time.second)

指针

Var a = New(int) //初始化a时一个指针变量 类型是*int 并分配空间

Make分配内存
Make只用于slice\map\channel的初始化,返回的还是这三个引用类型本身

Json数据

是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。
基本格式:
{
“a” : ”hello”,
“b” : “world”
}

序列化:结构体转换成json必须为公有 既首字母大写

 Jsonbyte , _ = json.marshal(s1)
Jsonstr := string (jsonbyte)

反序列化:json转化为结构体student

Var str ={“id”:12}’
 Var s1 student
Err := json.unmarshal([]byte(str), &s1)

If err != nil {
Fmt.println(err)
}

结构体标签
type 类型名 struct{
字段名 字段类型 ‘json: “ip”’ //对应的json字符串的key为ip
字段名 字段类型
……
}

Go mod
Go mod init 项目名称

Go get 网址 下载包和依赖

接口

Type 接口名 interface{
方法名1(参数列表1) 返回值列表1
方法名2(参数列表2)返回值列表2
……
}

如果接口里面有方法的话,必要通过结构体或者自定义类型实现接口中的所有方法

空接口

Type 接口名 interface{}
可以表示任意的类型
例:
Var a int
Var b 接口名
b=a //接口表示int类型

可以在map和切片中使用

类型断言

Type a interface{}
a = “你好”
V,ok := a.(string) //ok是个bool类型,v是类型名

可以用switch来判断类型
Switch a.(string){
Case int :
Case string :
Defult:
}

gorountine协程

可以理解为用户级线程,并发
Go 方法名称 //表示开启一个协程
主进程结束完毕 协程未执行完毕 则协程一定退出

解决:
用sync.waitgroup来使主线程等待协程执行完毕
sync.waitgroup.done() //协程计数器减一
sync.waitgroup.add() //协程计数器加一
sync.waitgroup.wait() //等待协程计数器为0

Runtime.numcpu() //获取当前计算机上面的cpu个数
Runtime.gomaxprocs(个数) //设置自己使用多少个cpu
runtime.Goexit():立即终止当前协程
runtime.Gosched():用于让出CPU时间片,调度器重新安排任务调度,还是有几率分配到它的

channel管道

Var 变量 chan 管道类型 //引用数据类型
Make(chan 元素类型,容量) //分配空间

发送(把数据放到管道中)
Ch <- 值
接收(从管道内取值)
X := <- ch //管道内的值赋给x

关闭管道 close(管道名)
For range必须关闭管道 否则会一直阻塞在for range
For 可以不用关闭

单向管道(默认使双向管道 可读可写)

make(chan<-, int , 2)	//只可写
make(<-chan, int , 2)	//只可读

capacity= 0 时,channel 是无缓冲阻塞读写的,无缓存的channel只有在receiver准备好后send才被执行。如果有缓存,并且缓存未满,则send会被执行
容量> 0 时,channel 有缓冲、是非阻塞的

Select多路复用

同时获取多个管道里的值
Select{
Case <-ch1:
Case data := <-ch2:
Case ch3 <- data:
……
Default:

}
如果没有case需要处理,则会选择default去处理,如果default case存在的情况下。如果没有default case,则select语句会阻塞,直到某个case需要处理

import "fmt"
func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:		//函数里这个case不阻塞,协程结束
            fmt.Println("quit")
            return
        }
    }}
func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {			//协程 用来判断输出了多少个菲波拉契数 需要十个
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0			//当quit管道里有0值时
    }()
    fibonacci(c, quit)}

超时处理

select有很重要的一个应用就是超时处理。 因为上面我们提到,如果没有case需要处理,select语句就会一直阻塞着。这时候我们可能就需要一个超时操作,用来处理超时的情况

func main() {
c1 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c1 <- “result 1”
}()
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println(“timeout 1”)
}}
输出结果为 timeout 1
互斥锁
var mutex sync.Mutex
mutex.Lock() //锁定
mutex.Unlock() //解锁

反射

Reflect包来实现

Reflect.typeof() //获取变量类型
Reflect.valueof() //获取变量的值
Reflect.kind() //获取种类

V := Reflect.valueof(空接口).int() //获取原始值
用siwtch v.kind{
} //来判断 int 为Reflect.int

通过反射来修改值

当为值时:
先获取值 v := Reflect.valueof()
再修改值 v.setint( ) //如果这个变量的类型为int

当为指针变量时:
v := Reflect.valueof()
v.elem().kind() //==Reflect.int
V.elem().setint()

结构体反射

Structfield类型 用来描述结构体中一个字段的信息
Type structfield struct{
Name string
Pkgpath string //非导出字段的包路径,对导出字段该字段为0
Type type //字段的类型
Tag structtag //字段的标签
Offset uintptr //字段在结构体中的字节偏移量
Index []int //用于type.fieldbyindex时的索引切片
Anonymous bool //是否匿名字段
}

先判断v := Reflect.typeof() 是否是结构体
然后通过类型变量里面的method可以获取结构体的方法
Method := v.method(0) //这和结构体方法的顺序没有关系,和结构体类型名的ascii码有关
或者 method := v.methodbyname(“…name…”)
调用该方法可以使用v.methodbyname(“…name…”).call(nil) //nil表示不传值

文件操作

读取文件

以切片的方式读取
File,err := Os.open(“绝对路径或相对路径”) //以只读打开 err==nil表示成功
file.read(切片) //读入到切片中 如果err = io.eof 表示读取完毕
用循环读取文件
Defer file.close() //关闭文件

以string方式读取
File,err := os.open()
创建reader对象 reader := bufio.newreader(file) //产生io.eof之后,可能buffer里边还有数据
readstring读取文件 line,err :=reader.readstring(‘\n’)
关闭文件流 Defer file.close()

通过ioutil读取文件
一次性读取
Ioutil.readfile(“路径”)

写入文件

Os.openfile(“路径”,os.o_create|os.o_rdwr(权限), 0666)
File.write([] byte(切片数据))
File.writestring(字符串数据)
关闭文件流Defer file.close()

Os.openfile(“路径”,os.o_create|os.o_rdwr(权限), 0666)
创建writer对象 reader := bufio.newwriter(file)
line,err :=reader.writestring(“写字符串”)
Writer.flush() //将缓存中的内容写入文件
关闭文件流Defer file.close()

3.Ioutil写入文件
Str := “hello”
Err := ioutil.wirtefile(“路径”,[]byte(str),0666)

文件重命名: os.rename(“文件路径”,”更改的名字”)

删除文件 os.remove()
删除多个文件 os.Removeall()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值