GO语言
优点:
- 编译速度快
- 运行效率直逼C语言
- 简单
- 并发牛逼到没有朋
/* Docker Codis Glow 类似于Hadoop Cockroach(蟑螂) */
package main import "fmt" func main() //入口函数 { fmt.Println("Hello World") }
golang语言特性
1.垃圾回收 a 内存自动回收,再也不需要开发人员管理内存 b 开发人员专注业务实现,降低了心智负担 c 只需要new分配内存,不需要释放 2.天然并发特性 a 从语言层面支持并发,非常简单 b goroute 轻量级线程,创建成千上万个goroute成为可能 c 基于CSP(通信序列进程)模型实现 3. channel(管道) a 管道,类似于unix/Linux中的pipe b 多个goroute之间通过channel进行通信 c 支持任何类型 package main import "fmt" func main() { pipe := make(chan int,3) //make 作用类似于new关键字 pipe <- 1 pipe <- 2 pipe <- 3 fmt.Println(len(pipe)) } 4.多返回值 a 一个函数返回多个值 package main import "fmt" func calc(a int,b int)(int,int){ sum := a+b avg := (a+b)/2 return sum,avg} func main(){ a,b := calc(10,20) fmt.Println(a,b) }
包的概念
1、和python一样,把相同功能的代码放到一个目录,称之为包 2、包可以被其他包所引用 3、main包是用来生成可执行文件,每个程序只有一个main()包 4、包的主要用途是提高代码的可复用性。
go语言基础
关键字:break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for inport return var go程序是通过package来组织的 main()函数是每一个独立函数的可运行程序的入口点 var: var关键字是go最基本的定义变量方式,与c语言不同的是go把变量类型放在变量名后面: var name string var age int var price float 简短声明 :=(注意:简短声明不能用于函数体之外,只能用于函数体之内) e.g v1,v2,v3 := 10,20,30 name:= "江西理工大学" const 常量: eg: const Pi int = 314 const hello string = "China"
数据类型
bool int int8 int16 int32 int64 float32 float64 complex64 complex128 string array 就是数组 var arr [n]type slice 是go的动态数组(切片) var fslice []int || s := make([]int,10,20) || 常用x := map /* package main import "fmt" func main() { x := [10] int{1,2,3,4,5,6,7,8} // 定义数组 y := x[1:3] // 切片 fmt.Println(x) // [1 2 3 4 5 6 7 8 0 0] fmt.Println(y) // [2 3] } */ import "fmt" func main() { y := make([]int,3,5) //产生一个切片 ,5表示容量,长度为3,make生成内存空间 fmt.Println(len(y),y) 3,[0 0 0] } package main import "fmt" func main() { y := make([]int,3,5) // 5表示容量,长度为3 fmt.Println(len(y),y) y1 := append(y,2,3,8,4,9,9) fmt.Println(y1) //[0 0 0 2 3 8 4 9 9] }
常用的go命令
/* 4个go命令: go命令 文件名 要么根据绝对路径去找,要么能在当前cmd路径下找到 go命令 项目名 去src下找 1 go run 编译并执行,不保存编译后的文件 2 go build 编译并保存,默认放在当前的cmd路径下;指定保存路径 -o 3 go install 编译并放在gopath下的bin目录下。 4 go fat 格式化,统一格式化项目比较多 */
变量
/* 变量声明五种方式: 1 var 变量1,2... 类型字面量 有默认值,int 0;bool false;string 空; */ package main import ( "fmt" ) // 声明一个变量 func main() { var a int var b string var c bool fmt.Println(a) //默认为0 fmt.Println(b) //默认为空 fmt.Println(c) //默认为false } /* 2 var 变量1,2... 类型字面量 = 变量值 (声明变量,给定初始值) */ package main import ( "fmt" ) // 声明变量给定初始值 func main() { var a,d int = 10,100 var b string = "hello world" var c bool = true fmt.Println(a,b,c,d) } /* 3 var 变量名1 = 变量名值 */ package main import ( "fmt" ) func main() { var a = 100 var c = "hello" var b = true fmt.Println(a,b,c) } package main import ( "fmt" "reflect" ) func main() { var a,b,c = 100,"Hello",true fmt.Println(a,reflect.TypeOf(a)) fmt.Println(b,reflect.TypeOf(b)) fmt.Println(c,reflect.TypeOf(c)) } /* 3 var 变量名1,变量名2、、、、 = 变量值1,变量值2、、、、、 */ package main import ( "fmt" "reflect" ) func main() { var a,b,c = 100,"Hello",true var d int64 = 20 // d 设置为int64型 fmt.Println(a,reflect.TypeOf(a)) // 默认为int fmt.Println(b,reflect.TypeOf(b)) // 默认为string fmt.Println(c,reflect.TypeOf(c)) // 默认为bool fmt.Println(d,reflect.TypeOf(d)) // 为int64 } /* 4 变量名1...:= 变量值1... 适用条件:只能用于局部 */ package main import "fmt" func main() { a := 100 // := 只能用在局部 fmt.Println(a) } /* 5 var(//变量组 变量名1...类型字面量 量名1... 类型字面量 = 变量值1... 变量名1.... = 变量值 ) */ package main import "fmt" func main() { var( a int = 10 b string = "江西理工大学" c,d = 10.2,true ) fmt.Println(a,b,c,d) }
变量赋值
- 先声明后赋值
- 赋值类型要一致
- a,b,c = 值1,值2,值3
- 交叉赋值
变量的命名规范
推荐使用驼峰体
小写开头,只用于本包下使用(projected)
大写开头,用于开放(public)
常量
/* 常量 内存权限只读 定义常量: const 常量名1 类型字面量 = 值1 ,没有初始值. //常量定义完可以不立即使用 const 变量名1 = 值1 const( 常量组 若没有指定类型和值,会继承上面最靠近它的非空常量,并且列数要相等 ) */ package main import "fmt" func main() { const a,b int = 100,10 //常量定义完,可以不立马使用 fmt.Println(a) fmt.Println(b) } package main import "fmt" func main() { const a,b = 100,20 fmt.Println(a,b) } package main import "fmt" func main() { const (//常量组 a,d int = 10,100 c string = "徐王娟" b bool = true ) fmt.Println(a,b,c) fmt.Println(d) }
自增常量组
/* iota 是从0开始计数 _ 占位符 占着茅坑不拉屎 iota 中断 定义一个值 iota 恢复 多个iota */ package main import "fmt" func main() { //自增常量组 const( a = iota //从0开始计数 b c d e = "江西理工大学" f g h = iota 中断 m n ) fmt.Println(a,b,c,d) // 0 1 2 3 fmt.Println(e,f,g) // 江西理工大学 江西理工大学 江西理工大学 fmt.Println(h,m,n) // 7 8 9 } package main import "fmt" func main() { const( a,b = iota,iota c,d e,f ) fmt.Println(a,b) //0,0 fmt.Println(c,d) //0,0 fmt.Println(e,f) //0,0 } package main import "fmt" func main() { const( _=iota+1 a b c d ) fmt.Println(a) //1 fmt.Println(b) //2 fmt.Println(c) //3 fmt.Println(d) //4 }
基本运算符
/* 数字与数字之间加减乘除,只要其中一个是小数,结果是浮点型,整形与整形之间加减乘除,结果一定是整形。 程序只会在特定情况下(遇到浮点型,不管是变量还是数字) 会把整形数字转成浮点型,再进行运算,但是不会自动转换整形变量 */ package main import ( "fmt" "reflect" ) func main() { var a = 1+2.0 var b = 3*a var c = 5.0*b fmt.Println(a,reflect.TypeOf(a)) fmt.Println(b,reflect.TypeOf(b)) fmt.Println(c,reflect.TypeOf(c)) }
/* 常量(const)存储方式和变量(var)存储方式不一样。 */ package main import ( "fmt" "reflect" ) func main() { const a = 3 var b = 2.5 var c = a/b fmt.Println(c,reflect.TypeOf(c)) }
流程控制语法
/* 用户交互: var name string fmt.Scanln(&name) // 传入指针内存地址 fmt.Println(name) */
// if - else语句 package main import "fmt" func main() { var age int //定义变量age fmt.Print("请输入你的年龄:") fmt.Scanln(&age) // fmt.Println(age) if age >= 25{ fmt.Println("阿姨你好") } else { fmt.Println("小姐你好") } }
package main import "fmt" func main(){ var score int fmt.Print("请输入你的成绩>>") fmt.Scanln(&score) if score >= 90{ fmt.Println("优秀") } else if score >= 70{ fmt.Println("去python9期吧") } else { fmt.Println("回家吧") } }
if - else if - else/ if[嵌套] package main import ( "debug/elf" "fmt" "go/ast" ) func main() { var score int fmt.Print("输入你的分数") _,err := fmt.Scanln(&score):if err != nil { fmt.Println("输入有误") }else { if score >= 90{ fmt.Println("成绩优秀") }else if score >= 70{ fmt.Println("成绩良好") }else { fmt.Println("回家歇着") } } }
/*if 可执行语句; 判断条件{ }*/ package main import "fmt" func main() { if fmt.Println("江西理工大学");true{ fmt.Println("电气工程与自动化学院") }else{ fmt.Println("控制工程") } }
// switch 分支语句 //switch 比if 更简洁明了 /* switch [可执行语句;] 判断量{ case 被判断量1,被判断量2: 代码 case 被判断量3: 代码 default: 代码 } */ package main import ( "fmt" ) func main() { var people string fmt.Println("来访客户:") fmt.Scanln(&people) switch people { case "男经理","女经理": fmt.Println("经理你好") case "客户": fmt.Println("客户你好") default: fmt.Println("不存在") } } /* switch 可执行语句;{ case 条件1,条件2: 代码块 case 条件3 } */ package main import "fmt" func main() { switch score:= 60;{ case score>= 90: fmt.Println("优秀") case score >= 70: fmt.Println("良好") case score >= 40: fmt.Println("不及格") } }
break 和fallthrough语句(很少用,能不用就不用)
//break 和fallthrough 主要为了 解决c和c++ package main import ( "fmt" ) func main() { var people string fmt.Println("来访客户:") fmt.Scanln(&people) switch people { case "男经理","女经理": fmt.Println("经理你好") case "客户": fmt.Println("客户你好") default: fmt.Println("不存在") } }
for 循环
/* 格式: for 初始条件;判断条件;追加条件{ 循环体代码 } */ package main import "fmt" func main() { for a:=1;a<=3;a++{ fmt.Println("江西理工大学") } } //省略初始条件 for ;循环条件;追加条件{ 代码体 } package main import "fmt" func main() { a:=1 for ;a<=3;a++{ fmt.Println("江西理工大学") } } //省略初始条件和追加条件 package main import "fmt" func main() { a:=1 for ;a<=3;{ fmt.Println("江西理工大学") a++ } }
for 循环退出
/* break continue 变量开关 */ package main import "fmt" func main() { for a:=1;a<=3;a++{ fmt.Println("河海大学") if a == 2{ coinunte } } }
标签(2019.7.17)
什么是标签? 记录被标签者的信息 在程序中记录当前代码位置 为什么要有标签? 标记不是目的,目的是使用,记录位置是为了快速找到它 怎么使用标签? 定义标签:直接在代码上加上标签名,大写+数字 和变量区分开。// 如:LABEL1 定义完标签就一定要使用标签。 使用标签: 1 break + 标签 2 continue + 标签 // 结束被标记的循环 3 goto + 标签 // 降低了代码的可读性和可维护性,能不用则不用 注意点: 1 只能用于函数内部跳转 2 不能挑过变量声明
基本数据类型及其操作
硬盘(utf-8) 内存(utf-16) /* 整型: 有符号:int int8 int32 int64(正常使用:int,int64,uint uint64) 无符号:uint uint8 uin64 uint64 浮点型: float32 float64 float32 显示8位,精确到7位 float64 显示17位,精确到16位 复数类型 complex64(complex里,a,b 皆为float32) complex128(complex里,a,b 皆为float64) 强制类型转换: eg: var a int8 = 123 var b int64 = int64(a) //强制转换 fmt.Println(b) 数字类型和数字类型之间进行转换,转换类型要能够完全表示被转换类型。 字符串类型: string 字符串的操作。 支持 != + > < 字符串输出格式化: fmt.Printf( "XXX,%d",a) 遍历 for i,v:= range "江西理工大学" fmt.Printf("%d,%c\n",i,v) */ package main import ( "fmt" ) func main() { var s string = "Jiangxi University of Science and Techlonogy" //定义字符串变量 for i,v:= range s{//遍历 fmt.Printf("%d,%c\n",i,v) fmt.Println(string(v)) } }
备注
switch[可执行语句;]判断量{ case 被判断量1,被判断量2...: //相当于 if 判断量 == 被判断量1||判断量 == 被判断量2 代码 break //用于提前终止switch,后面的代码不会执行 代码 fallthrough // 用于跳过下一个case判断,直接执行代码,fallthrough 必须写在最后 case 被判断量3: 代码 ..... default: //相当于else,所有case都不能满足时,才执行 代码... } for循环语句: for 初始语句;判断条件;追加语句{ 执行体 } 标签:定义(大写+数字),定义完一定得使用,标记的代码位置 1. break + 标签 //快速结束被标记循环 2. continue + 标签 // 跳过被标记循环的本次循环 3. goto+ 标签: 只能用于内部跳转,不能挑过变量声明语句 // go语言切片中没有步长。
String 包
Go语言是为了简化字符串的复杂操作,在标准库中提供了一个名为Strings的包,里面集成了很多功能,我们之间调用就好,不需要再自己编写。 string包:字符串常用操作。 1.判断是否以...开头,// string.HasPrefix(str,"") eg: /* package main import ( "fmt" "strings" ) func main(){ str := "上海浦东新区张江镇" //strings包中的HasPrefix() 检测以...开头 str2:= "jiangxi university of science and technology" str3:= "TOM IS HELLO" str4:= "###golang##" str5:= "Jiangxi\nand\t" str6:= "a,b,c,d,hello" fmt.Println(strings.HasPrefix(str,"浦东")) //false fmt.Println(strings.HasPrefix(str,"张江镇")) //false fmt.Println(strings.HasPrefix(str,"上")) //true fmt.Println(strings.HasSuffix(str,"张江镇")) //以....结尾 fmt.Println(strings.HasSuffix(str,"新区")) //false fmt.Println(strings.Contains(str,"江西")) //false fmt.Println(strings.Contains(str,"浦东")) //True fmt.Println(strings.ContainsAny(str,"张")) //true fmt.Println(strings.ContainsAny(str,"吴")) //false fmt.Println(strings.Index(str,"海")) //索引值 3 ,一个汉字占3个字节 fmt.Println(strings.Index(str,"")) //索引值为0,字符串开头默认值为0 fmt.Println(strings.LastIndex(str,"镇")) // 24 fmt.Println(strings.LastIndex(str," ")) // -1 fmt.Println(strings.Replace(str,"张江镇","康桥镇",1)) // 原来字符串替换新的字符串 fmt.Println(strings.Replace(str,"浦东新区","黄浦区",-1)) // -1 表示全部替换掉 fmt.Println(strings.ToUpper(str2)) //小写改成大写 fmt.Println(strings.ToLower(str3)) // 大写变成小写 fmt.Println(strings.ToTitle(str2)) // 等同于 ToUpper fmt.Println(strings.Trim(str4,"#")) // 除去指定字符 fmt.Println(strings.TrimSpace(str5)) // 除去空格等字符 fmt.Println(strings.Split(str6,",")) //变成切片 [a b c d hello] } */ 2.判断是否以...结尾。Strings.HasSuffix(str," ") 3.是否包含...。contains(str,"...") 4.是否包含...中任意字符 ContainsAny(str,"....") 注: contains 和 containsAny区别: fmt.Println(strings.Contains(str,"")) //true fmt.Println(strings.ContainsAny(str,"")) //false 5.查找...的第一次出现的所有...,Index(str,"...") 汉字一个字节占3位 6.从后往前找,第一次出现的索引. LastIndex(str,"...") 7.替换Replace(str,oldstr,newstr,n) // oldstr为老字符串,newstr为新的字符串,n为替换次数,n=-1,全部替换掉 8.统计字符串出现次数 count(str,"...") 9 大小写之间转换 ToUpper(str)/ ToLower(str) 10 单词大写 ToTitle(str) 11 除去指定字符 Trim(str,"...") #除去左右两边指定的字符(除去指定字符(首/尾)) 12 除去右侧字符 TrimRight(str,"....") 13 除去左侧字符 TrimLeft(str,"...") 14 除去空格字符 Trimspace(str) 15 split(str,"...") 根据指定分隔符,转成切片[a b c d...] 16 拼接,Join(字符串切片,拼接符)
strconv 包(字符串转换包)
/* strconv包 conv->convert(转换) */ 1 bool 转 字符串:FormatBool(bool值) 将布尔值转换为字符串 2 字符串 转 bool: ParseBool(str) //str 为 1,t,T,TRUE,true,True 或者 0,F,f,FALSE,False,false 当str不是 1,t,T,TRUE,true,True 或者 0,F,f,FALSE,False,false时,如"江西理工大学" var v,err = strconv.ParseBool("江西理工大学") fmt.Println(v) //false fmt.Println(err) // strconv.ParseBool: parsing "江西理工大学": invalid syntax 3 int64类型 转换为 字符串;strconv.FormatInt(int64,进制数) //把int64转换成相应进制,然后以字符串显示 字符串 转 int64 ; strconv.ParseInt(str,参数进制数,范围)// eg: strcov.ParseInt("123",参数的进制数,范围) 如范围:8 -128~127 代码示例: package main import ( "fmt" "reflect" "strconv" ) func main() { var a bool = true b:= "true" var c = "江西理工大学" fmt.Println(strconv.FormatBool(a)) //将bool型转化为字符串类型 fmt.Println(reflect.TypeOf(strconv.FormatBool(a))) fmt.Println(strconv.ParseBool(b)) // 将字符串转化为bool型 var v,err = strconv.ParseBool(c)// v表示结果(true or false),err表示返回错误信息。 fmt.Println(v) fmt.Println(err) var v1,err1 = strconv.ParseBool("t") fmt.Println(v1) fmt.Println(err1) //没有错误信息时,返回nil fmt.Println("*************************************************") var v2,err2 = strconv.ParseBool("oldboy education") fmt.Println(v2) fmt.Println(err2) fmt.Println("********************************") var v3, err3 = strconv.ParseBool("f") if err3 == nil{ fmt.Println("转换成功",v3) }else { fmt.Println("转换失败",v3) } var d = strconv.FormatInt(int64(46),5) //将46转换为5进制数 fmt.Println(d,reflect.TypeOf(d)) fmt.Println("**********************************") var str = "520" var v4,err4 = strconv.ParseInt(str,32,9) fmt.Println(v4) fmt.Println(err4) }
map类型(映射)
map类型 字面量 定义 操作 增 删 改 查 遍历 类型字面量 map[ktype]vtype ktype:是映射中键的类型,强调:此类型要能够判断 “==” vtype:是映射中值的类型,可以是任意类型。 定义:var 变量 类型字面量 变量 = 类型字面量{} package main /* map类型定义操作 */ import "fmt" func main() { var mymap map[string]string //定义一个map类型,系统默认自动给其赋值,不能再为mymap进行赋值操作, // 如mymap["name"] = "Kevin" //报错 // fm.Println(mymap) fmt.Println(mymap) fmt.Println(mymap == nil)//true youmap:= map[string]string{"name":"徐王娟"}//简短声明一个youmap变量 //var youmap = map[string]string = map[string][string]{"name":"徐王娟"} fmt.Println(youmap)//map[name:徐王娟] hemap:= map[string]string{} //赋初始值为空值 fmt.Println(hemap == nil) //false } /* map映射的操作 */ 1.赋值/改值操作 mymap:= map[string]string{} //声明一个mymap mymap["school"] = "江西理工大学" //增加操作 fm.Println(mymap) mymap["school"] = "河海大学"//更改值操作 var v,isexist = map["sex"] //判断"sex"是否存在map中 mymap["gender"] = "male" //添加{gender:male} mymap["address"] = "shanghai" //添加address:shanghai 2.删除操作:delete(map,key) delete(mymap,"gender") //删除指定键 package main import ( "fmt" ) func main() { mymap := map[string]string{} //生成一个mymap,其初始值为空值 fmt.Println(mymap) mymap["school"] = "江西理工大学" //增加操作 fmt.Println(mymap) mymap["school"] = "安徽大学" //修改 fmt.Println(mymap) var v,isexists = mymap["sex"] // 判断sex是否存在于mymap中 fmt.Println(v,isexists) mymap["gender"] = "male" fmt.Println(mymap) mymap["language"] = "Go" fmt.Println(mymap) delete(mymap,"gender") // 删除操作 fmt.Println(mymap) mymap["location"] = "China" for k,v:= range mymap{ // map遍历 fmt.Println(k,v) } } 3.遍历 package main import "fmt" func main() { mymap := map[string]string{} mymap["name"] = "徐王娟" mymap["age"] = "28" mymap["gender"] = "male" mymap["huji"] = "Anhui" for i,v := range mymap{ fmt.Println(i,v) } } } /* name 徐王娟 age 28 gender male huji Anhui */
包
在包中,如果变量名是小写,在包内可以相互访问,相当于JaVa中的projected。 在包中,如果变量名是大写,可以被包外所访问,相当于Java中的public。
函数定义与使用
定义: func 函数名(形参1 类型1,形参2 类型2,...)(返回值类型1,返回值类型2){ 代码体 return 返回值1,返回值2,... } 注:go语言不支持函数的默认参数 package main import ( "fmt" "reflect" ) func test1(x int,y string){ fmt.Println(x,y) } func test2(x,z int,y string){ fmt.Println(x,y,z) } func test3(x...int){ //x...int为变参 fmt.Println(x)//x输出为切片 } func test4(x...int)(int,string,string){ //定义返回值 fmt.Println(x) fmt.Println(reflect.TypeOf(x)) return 1,"hello world","返回值" //返回值 } func main() { test1(1,"hello") test2(1,3,"go") test3(1,2,3,4,5,6) //产生一个切片 fmt.Println(test4(3,5,6,3,2,2)) } ***************************************************************************************** /* 命名返回值 */ package main import "fmt" func test()(aaa int,bbb int){ // aaa int 默认为0,bbb int 默认为0 return } func main() { a,b:= test() fmt.Println(a,b) // 0,0 } **************************************************************** package main import "fmt" func test()(aaa int,bbb int){// aaa = 123 bbb = 123 return } func main() { a,b:= test() fmt.Println(a,b) //123,123 } *************************************************************** package main import "fmt" func test()(aaa int,bbb int){// aaa = 123 bbb = 123 return 1,2 } func main() { a,b:= test() fmt.Println(a,b) //1,2 }
函数变量
package main import ( "fmt" "reflect" ) func test(){ fmt.Println("我是函数变量") } func main() { fmt.Println(test) // 将函数名当做变量,输出的是 函数内存地址 x := test fmt.Println(reflect.TypeOf(x)) x() } /* 函数类型字面量: func(参数 类型, 参数 类型)(返回值类型1,返回值类型2...) */
函数嵌套定义
在go语言里面不支持一个func下出现另一个func,所以要实现函数嵌套,就得用变量声明的方式 去声明函数。 eg: package main import "fmt" //函数嵌套 func test(){ var test1 = func() {// var声明一个函数 fmt.Println("我是内部函数") } test1() } func main() { test() } 注:go不支持多个func()连用,所以得用声明变量的方式。如上所示。
匿名函数
go里 函数变量名存放的是函数内存地址 说明:我们定义函数的时候,其实就是定义了一个变量,只不过这个变量的类型是函数类型 函数类型:func 函数名(形参类型1,形参类型2...) (返回值类型1,返回值类型2...) 既然知道了函数类型,那么我们很明显可以用声明变量的方式去声明函数: 变量:= 函数类型(值--函数体)。 eg: test1 := func(){fmt.Println("我是test1")} test2 := func(x int){fmt.Println("我是test2,我有参数%v\n",v)} test3 := func()string{return "我有返回值"}
函数作用域
语法块: {}扩起来的叫做一个语法块,其内部变量就是局部变量,{}外面的叫做全局变量 作用域: {}叫局部作用域 {}外面叫做全局作用域 查找:局部作用域——>全局作用域 package main import "fmt" var a int = 10 // 全局变量 func test(){ a = 20 //局部作用域 { a = 100 //函数体局部作用域 } fmt.Println(a) } func main() { fmt.Println(a) //a = 10 test()//a = 100 }
闭包函数
panic恐慌
程序出错:1.编译阶段就会出错 2 运行时出错 package main import "fmt" func test(){ fmt.Println("我进来了") panic("我是一个错误信息") fmt.Println("我走了") } func main() { test() }
面向对象
结构体
/* 结构体: type 变量名 struct{ 字段名 类型, 字段名1 字段名2 类型, ... } */ eg: package main import "fmt" type student struct { //定义一个学生的结构体 name string age int gender string id int } func main() { var xwj = student{ //相当于实例化 name:"徐王娟", age: 23, gender:"male", id: 6720160375, } fmt.Println(xwj) fmt.Println(xwj.age) //打印xwj中的age属性值,访问字段 xwj.age = 28 //修改属性值 xwj.name = "蓝河" xwj.id = 320238025 xwj.gender = "female" fmt.Println(xwj) } /* 实例化对象没有初始值时 */ package main import "fmt" type person struct { //定义一个person类的结构体 name string age int loc string id int } func main() { var p = person{//以实例化一个结构体 //name:"李明", //age:26, //loc:"上海", //id:340823, } fmt.Println(p) // 0 0 } /* 传递给函数 */ package main import "fmt" type animal struct { //定义一个结构体 name string age int gender string } func test(aa animal){ aa.name = "阿狗" } func main() { var dog = animal{ //实例化结构体对象 name: "阿黄", age: 20, gender:"male", } test(dog) fmt.Println(dog) //{阿黄 20 male} } eg: package main import "fmt" type animal struct { //定义一个结构体 name string age int gender string } func test(aa *animal){ //*传递指针 aa.name = "阿狗" } func main() { var dog = animal{ //实例化结构体对象 name: "阿黄", age: 20, gender:"male", } test(&dog) //传入地址 fmt.Println(dog) // {阿黄 20 male} }
匿名结构体
/* 匿名结构体就是我们不自定义结构体类型,直接通过结构体字面量的形式产生一个实例(只用一次) eg: var 变量名 = struct{ }{} */ package main import "fmt" func main() { var test1 = struct { name string id int }{name:"孙悟空", id:340823} fmt.Println(test1) //{孙悟空 340823} } ************************************************* package main import "fmt" func main() { var test1 = struct { name string id int }{} fmt.Println(test1)//{0} }
结构体嵌套
package main import ( "fmt" ) type classes struct {//定义一个classes结构体 className string } type teachers struct {//定义一个teachers结构体 teachersName string class classes } type students struct {//定义一个students结构体 studentName string class classes } func main() { class1 := classes{//实例化class1结构体 className:"江西赣州", } teachers1 := teachers{ //实例化teachers结构体 teachersName:"何凯文", class:class1, } students1 := students{ studentName:"徐王娟", class:class1, } fmt.Println(teachers1) fmt.Println(students1) fmt.Println(teachers1.class.className) //访问classes中的className值 }
匿名字段
go语言中的方法
/* 方法的定义: 方法就是函数,只是这个函数是绑定给指定类型的,只有该类型的数据才能调用 func(参数 指定类型) 函数名(参数及类型) 返回值类型{ 代码体... } */ eg: package main import "fmt" type students struct {//定义一个students结构体 name string } func(s *students)change(name string){//*student,如果不加*,则没有改变,方法中的参数传入 s.name = name } func main() { student1 := student{ name:"孙悟空", } student2 := student{ name:"贝吉塔", } student1.change("孙悟饭") student2.change("特南克斯") fmt.Println(student1) //孙悟饭 fmt.Println(student2) //特南克斯 } *********************************************************************** package main import "fmt" type student struct {//定义一个student结构体 name string } func(s student)change(name string){ s.name = name } func main() { student1 := student{ name:"孙悟空", } student2 := student{ name:"贝吉塔", } student1.change("孙悟饭") student2.change("特南克斯") fmt.Println(student1) //孙悟空 fmt.Println(student2) //贝吉塔 } ********************************************************************** package main import "fmt" type students struct {//定义一个students结构体 name string //存放学生姓名 score []int // 存放学生成绩(切片) } //定义一个方法,用来给学生添加成绩 func (student *students) appendScore(score int){ //student *student 绑定方法 student.score = append(student.score.score) } func main(){ student1 := students{ name:"弗利萨", } student1.appendScore(90) student1.appendScore(100) fmt.Println(student1) }
接口 (interface)
接口(interface)核心知识点 1、任何类型的数据都可以传给(interface) 2 interface 统一了功能调用方式 统一调用方式的意思是:接口只管统一功能调用方式,不管函数怎么实现的。 3 interface 不管功能的实现。 那函数实现交给谁? 1.谁要传进来就由谁来实现。 2.实现了接口里所有函数的,叫做实现了这个接口 定义接口: type 接口名 interface{} /* 任何类型的数据都可以传给interface */
接口断言
我们知道了接口的核心是接收任意类型,统一调用方式 现在由这么个需求,假设我有一个接口,可以接收结构体类型a和字符串类型b,但我现在需要根据不同的类型写不同的代码,这怎么处理?很明显,这里需要一个类型判断 断言,就是用来处理接口类型的判断 var v,ok = 具体接口(实现了接口的类型a) // ok得到了是bool值,用来判断传入接口的类型是不是类型a // 如果ok为true,则v就会得到该类型的值,否则就是类型a的初始值
接口嵌套
type mine1 interface{ test1() test2() } type mine2 interface{ mine1 test3() } /* mine2就相当于: type mine2 interface{ //程序自动拓展开 test1() test2() test3() } */
type switch(类型选择)
/*type switch和switch的用法基本上是一致的*/ switch t:= 具体接口(type){ case mystring: 代码 case mystruct: 代码 ... dafault: 代码 }
回顾
1 map 类型 map[string]string var 变量名 类型字面量(map == nil) 接口: 1.任何类型都可以传给接口 2.统一了调用方式 3.不负责方法的实现 谁要传给接口,就由谁去实现方法(绑定方法的的方式) 实现了接口中规定的所有方法,叫做实现了这个接口 只有实现了这个接口的类型才可以传递给接口 type 接口名 interface{ 方法名(形参类型 新参类型) 返回值类型 } var 接口 接口名 接口 = 类型 (绑定方法,至少需要绑定接口中所有的方法) 接口.方法名()
补充
继承方法: type school struct{ schoolName string } type struct2 struct{ studentName string } func()
并发
用户级线程 和 系统级线程 内核级线程: 内核级线程是操作系统执行程序的最小单元,就是说:CPU会在内核级线程之间切换并执行,如果有多个cpu,那就是多个cpu这些线程之间切换并执行。我cpu去执行的就是内核级线程。 用户级线程: 用户级线程说的简单直白一点,就是用用户自己规定的一个代码块。 常见并发设计模式: 1.协程设计模式(用户级线程和内核级线程之间多对一,需要切换) //一旦发生无法切换的阻塞,整条内线程都会被阻塞 //这个模式的优点在于开销小,切换效率快,但有也有两个很致命的问题:一,就是不能实现并行,二,就是一旦阻塞整个线程都会被阻塞。python里的gevent就是这个模式。 2.多线程设计模式(用户级线程和内核级线程之间一对一) //一对一绑定,由操作系统调度进行线程间的切换,真正意义上做到了并行 这个模型的优点在于简单、和并行。缺点:一、切换操作系统调度的,效率比较低。二,Linux操作系统下开一个线程默认需要8M空间,资源成本大。 3.go并发设计模式(将 多对一模式 和 一对一模式 结合起来) 4.
创建go并发
1.创建gorounte: 格式如下: go函数名(参数) 或者用匿名函数创建: go func(形参) {函数体}(实参) package main import "fmt" func test1(){ fmt.Println("我是test1") } func test2(){ fmt.Println("我是test2") } func main() { for i:=0;i<10;i++{ go test1() go test2() } var myinput string fmt.Scanln(&myinput) // 开go并发进程 }
通道channel
正常多线程,比如python里Threading,都是以共享内存的方式来进行数据交换 这时,我每个线程都可以访问同一个数据,并对它进行修改,这就造成了数据的不安全,为了保证数据修改的正确性,就得用互斥来解决这个问题。这样虽然问题解决了,就是造成了性能的下降。 go就与众不同,它不用共享内存的方式共享数据,它用通道的方式来共享数据。
通道的声明
我们使用make关键字来创建一个通道
mychan:= make(chan 类型) //chan:表示通道 ;类型:用来指定通道里数据的类型
收发数据
我们用<-来收发数据
发数据
mychan <- 数据
收数据
数据 <- mychan
```