Golang 初识
注意事项
,变量字符只能用双引号("")
,多个字符串拼接用 + 号连接
,常量只能声明布尔型,数字型【整数型、浮点型和复数】,字符类型
,可见的外部函数、变量和方法以大写字母开头【常用:不同文件对函数、变量的调用】。
,func 形参参数类型定义
,当传递文件类型时
file *multipart.FileHeader
名词解释
nil:
表示一个指针、切片、映射、通道、接口或函数类型的零值或空值。它用于表示这些类型的变量当前不指向任何有效的对象或数据结构
局部变量:
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
全局变量:
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
备注:
1.局部变量不会一直存在,在函数被调用时存在,函数调用结束后变量就会被销毁,即生命周期。
2.Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
函数传值
值传递:
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
结构体
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
细节整理
初始化优先级
// 全局变量
// eg 1
var num = getNum()
func getNum() int{return 0}
// init 函数
func init(){}
// main 函数
func main(){}
执行优先级 全局变量 > init() > main()
// eg 2
// import 导入别的包中含有变量、init()函数
// 当前文件
var num = getNum()
func getNum() int{return 0}
// init 函数
func init(){}
// main 函数
func main(){}
执行优先级 import导入包中的全局变量 > import导入包中的init()函数 > 当前文件全局变量 > 当前文件init() 函数> 当前文件 main()
语法细节
断言
在这里插入代码片
结构体嵌套重复变量优先级
type person struct{
name string
}
type allperson struct{
person
name string
}
func main(){
var allp allperson
// 情况 1
// 当结构体allperson 中不存在 name 变量时,此赋值方式直接赋值到 person结构体中的name变量
// 等同于 allperson.person.name
// 情况 2
// 当结构体allperson 中存在 name 变量时,此赋值方式仅赋值到 allperson结构体中的name变量
allperson.name = "small-pig"
// 当结构体嵌套时可通过简写方式访问被嵌套结构中的变量
// eg (allperson 结构体中不存在 name 变量的情况下)
allperson.name = "small-doc"
}
函数中定义未知的多个形参
//,id -- 具体参数
//,data -- 未知参数(不限个数、可为null)(data可以理解为多个参数形成的slice)
// type - 未知参数的类型(任意类型可用interface{}代替)
func getUser(id int, data ...type){
for key, param := range data {
}
}
// 调用时(此时函数体中 data 为2个参数)
getUser(1, paramA, paramB)
占位符
常用于fmt.Printf() 函数中
,用法
fmt.Printf(placeHolder, "strings")
,具体占位符
%T -- 获取变量类型
%s -- 字符类型
%q -- Unicode 转字符,并且增加单引号(不论整数还是字符,转换为都加)
%v -- err错误信息替换
%f -- 浮点型
%d -- 整型
结构体转json时忽略为空的字段
// 关键词 omitempty,当转换成json时该字段为空的时候不显示该字段
type info struct{
Id int `json:"id"`
Name string `json:"id"`
Img string `json:"img,omitempty"`
}
基础语法
字符格式化与输出
,引入fmt 包
import "fmt"
,fmt.Sprintf() -- 根据格式化参数生成格式化的字符串并返回该字符串
,fmt.Printf() -- 根据格式化参数生成格式化的字符串并写入标准输出。
,fmt.Println() -- 字符输出
,fmt.Errorf() -- 返回 error 类型的错误
数据类型
,布尔 (bool)
,数字类型 (int,float)
,字符类型(string)
,派生类型
,指针类型(Pointer)
,数组类型
,结构化类型(struct)
,管道化类型(channel)
,函数类型
,切片类型
,接口类型(interface)
,map类型
init
,string
var valString = "contents"
,int
var varInt = 1
,array
,standad(标准)
var array = [arrayLen]type{ele1, ele2, ele3}
arrayLen -- 数组长度【超出报错】
... -- 表示不限制单独
type -- 数组元素类型
ele1 | ele2 | ele3 -- 数组元素
,slice -- 切片
,标准
var slice []type = make([]type, len, cap)
type -- 类型(int,string,float)
len -- 长度【必须】
cap -- 容量【与长度含义不一致】【必须】
attendtion:
int | float32 | float64 类型声明的切片各元素默认为0
string 类型什么的切片各元素为空字符
,简写
slice := make([]type, len, cap)
,切片初始化【直接插入数据】
slice := [] type{element1,element2,element3}
type -- 类型(int,string,float)
element1 | 2 | 3 -- 切片元素
,map - 集合
,standad 【标准】
var map = make(map[keyType]valueType, len)
keyType -- 集合key类型
valueType-- 集合value类型
len -- 初始化长度【当容量不足时会自动扩充】
,map init val
var map = map[keyType]valueType{
"key1":"value",
"key2":"value",
}
,struct -- 机构题
type structName struct{
ele1 type
ele2 type
}
ele1 -- 元素名称
type -- 元素类别
,interface - 接口
type interfaceName interface{
}
,channel - 管道
// 特性
// channel 不用预先定义直接初始化也可以
// 管道里面只能有一种类型
// 管道必须用make 初始化后才可以赋值
// 管道被关闭后不能再插入值
// 定义管道
var var_name chan var_type
eg
var ageCh chan int
// make 初始化
chanName := make (chan var_type)
Typeof convert
attention:
assignment var type == convert type (赋值变量类型必须等于转换类型)
var varString string = "hellowolrd"
,string => int
var varInt int
varInt = strconv.Atoi(varString )
attnetion :
varString is int num => return int num
varString is not num => return 0 [int]
,string => float64|32
var varFloat float32|64
attention:
varString is float => return int float
varString is not float => return 0 [int]
,int => string
varString = strconv.Itoa(varInt)
,int => float64 | 32
varFloat = float64(varInt)
,float => int
varInt = int(float)
,string => []byte
byteStr := []byte(string)
,[]byte => string
str := string(byteStr)
数据类型初始化
,数值类型:0
,布尔类型:false
,字符串:""【空字符串】
,指针:nil
,整数类型的变量
var a *int
,切片类型的变量
var a []int
,映射变量
var a map[string] int
,整数类型的通道变量
var a chan int
,函数变量
var a func(string
,接口类型
var a error
变量声明
,非常量
,单个
var age int = 1 <=> age := 1
,多个
var name1, name2, name3 = v1, v2, v3 <=>n ame1, name2, name3 := v1,v2,v3
,常量
# 需注意 iota 用法
# 常量只能声明布尔型,数字型【整数型、浮点型和复数】,字符类型
,单个
const MAN int = 1 <=> MAN = 1
,多个
const name1, name2, name3 = v1, v2, v3
,多个,实例2
const (
name1 = 0
name2 = 2
)
函数
函数传值
,值传递 【默认,不举例子】
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
,引用传递
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
func main(){
age := 1
content := "小主小主"
funcval(age, content)
}
/**
* 引用传值,关键字 *
*/
func funcval(age *int, content *string){
*age = 10
*content = "小猪快跑"
}
函数可变实参
// 用于函数中参数数量可变的传递
func test(args ...int) {
// args 是切片类型
}
test(1,2,3,4)
闭包函数
特点:
匿名函数中引用的变量会一直存在内存中,不被销毁
func _anonymous() {
f := _getNum()
fmt.Println(f(1))
fmt.Println(f(2))
fmt.Println(f(3))
}
// 匿名函数中引用的变量会一直存在内存中,不被销毁
func _getNum() func(int) int{
var sum int = 0
return func(i int) int {
sum = sum +i
return sum
}
}
结构体
,关键词
type:固定声明关键词
typeName:结构体名称
struct:声明结构体中不同(相同)类型字段的固定前缀
标签:待更新
,声明实例
type typeName struct {
name1 string
naem2 string
age int
}
,访问结构体成员
typeName.name1
,使用实例
,基础赋值
,按顺序依次赋值
typeName{"小猪佩奇", "小猪"}
,字段赋值【可打乱顺序】
typeName{title:"小猪佩奇", age:1,}
,注:
,以上两种赋值后不能直接使用,需赋给新的变量才可使用
,结构体中的字段可以不进行赋值
typeNames := typeName{title:"小猪佩奇", age:1,}
,special
,go 序列化 结构体 小写变量
结构体json序列化时,只有大写字母开头会进行转换,为避免这类问题可以定义结构体标签来解决
type typeName struct {
Name1 string `json:"name1"`
Naem2 string `json:"name2"`
Age int `json:"age"`
}
未加标签序列化输出
{ "Name1":"aaa","Name2":"bbb","Age":1 }
加标签序列化输出
{ "name1":"aaa","name2":"bbb","age":1 }
,实现结构体类型 的string 方法,在输出结构体时会自动输出字符
type person struct{
Name string
}
func (p *person) String() string {
str := fmt.Sprintf("aaaaa-name: %s", p.Name)
return str
}
func main(){
var p person
p.Name = "small pig"
fmt.Println(&p)
// 输出结果为 aaaaa-name small pig
}
循环 – 范围查询 (for – range)
,for loop scope support type : array,slice,map,string
get key, value
for key, value := range array{
}
only value
for _, value := range slice{
}
切片(slice)
,初始化
var slice []type = make([]type, len, cap)
<=>
slice := make([]type, len, cap)
,初始化数据声明
slice := [] type(ele1,ele2,ele3)
,get slice data
,get all
allslice := slice[:]
,create a new slice of the elements in arr from the subscript startIndex to endIndex-1.
attention: index start from 0
partSlice = slice[1:3]
,get slice length
len(slice)
,get slice cap
cap(slice)
,adding element to slices
sliceNew := append(slice,1,2,3)
,copy slice
attention:Slices must be created first when copying
newSlice := make([]int, len, cap)
copy(newSlice, slice)
集合(map)
,init map
mapVar := make(map[keyTupe]valueString, Num)
keyTupe -- key 类型
valueString -- value 类型
Num -- map 元素 个数【当map集合中元素超过指定个数时,go会自动扩充】
,init map assignment value
mapVar := map[keyTupe]valueString{
"name":"small pig",
"content":"small lovely dog",
}
,map define different values
var maps = make(map[string]interface{})
maps ["id"] = 1
maps ["name"] = "small-pig"
maps ["flag"] = true
attention:
if you use this is method ,you should perform type conversion
for example
ages := maps["id"].(int) + 2
,verify if the key exists
val,res = mapVar[key]
val -- map[key] 中的值
res -- 值是否存在的结果
true -- exists
false -- not exists
,set map element value
mapVar["name"] = "small pig"
,get map length
mapLen := len(map)
,delete map length
delete(mapVar, "mapKey")
接口(interface)
// 接口定义
type numCount interface {
sums() int
}
// 人数和结构体
type manSum struct {
anum int
bnum int
}
// 自定义和结构体
type customSum struct {
num int
}
// manSum 结构体 实现接口(numCount)中的方法(sums)
func (manSum manSum) sums() int{
return manSum.anum * manSum.bnum
}
// customSum 结构体 实现接口(numCount)中的方法(sums)
func (customSum customSum) sums() int {
return 5 + customSum.num
}
// 接口调用
func interfaceExec() {
// 该行可注释
var numCount numCount
numCount = manSum{anum: 10, bnum: 5}
fmt.Println(numCount.sums())
numCount = customSum{num: 10}
fmt.Println(numCount.sums())
}
// 代码含义
以上实例中,我们定义了一个 sumCount 接口,它定义了一个方法 sums(),该方法返回一个 int 类型的面积值。然后,我们定义了两个结构体
manSum 和 customSum,它们分别实现了 sumCount 接口的 sums() 方法。在 interfaceExec() 函数中,我们首先定义了一个 sumCount
类型的变量 numCount,然后分别将 manSum 和 customSum 类型的实例赋值给它,并通过 sums() 方法计算它们的面积并打印出来,
通道(channel)
特性:
,共性
,通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。
,已关闭的channel 再次关闭时会 panic(抛出异常)
,different
,常规 channel
,当没有接受者向 channel 传递时值时会抛出异常(锁阻塞)
,可以理解为同步channel
,缓冲区 channel
,channel 中没有数据时不能接受数据,否则 panic
,channel关闭后且缓冲区还有数据,当接受数据时返回true,其他情况返回false
,当缓冲区塞满之后不能追加,只能等待channel释放元素才可添加,此时channel保持阻塞
,当channel未收到数据元素时保持阻塞,只到将元素拷贝到channel才接触阻塞(channel 收到一个元素即可解除阻塞状态)
【注:是在代码中有for select 情况下才可以】
声明
普通:
chan := make(chan type)
// int 类型通道
chan := make(chan int)
带有通道缓冲区
chan := make(chan type, num)
// int 类型通道 且 带有1个长度的缓冲区
chan := make(chan int, 1)
协程(goroutines)
主死协从:当主进程执行结束后、不论协程有没有在执行都将结束运行