go语言基础
2019-08-18 18:48 錾子 阅读(104) 评论(0) 收藏 举报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
浙公网安备 33010602011771号