Go 编程基础

Go编程基础

go run 直接运行可执行的程序
go build 运行且生成该系统下的可执行文件
栈:先进后出
堆:先进先出

1.定义

全局变量必须通过 var i int 定义
支持多重赋值 i,j=j,i

2.常量

const 常亮的赋值是编译行为,不是运行期行为
iota出现一次,常亮值+1,但是出现下一个const,iota重置为0
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
两个 iota赋值语句相同,可以省略表达式
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 <<iota // a == 1 (iota在每个const开头被重设为0)
b // b == 2
c // c == 4
)

3.变量

  以大写字母开头,在包外可见
  不同整型的强制转换
  var a int=35
  var b int64
  b=int64(a)
  &&两个为真,真, ||一个为真,真,运算符优先级,&&高于||
  字符串内容初始化后,不能修改
  str := "Hello world" // 字符串也支持声明时进行初始化的做法 
  str[0] = 'X' // 编译错误
  字符串连接用+
  “hello”+"134" //结果为hello134

4.数组

4种数组的初始化方式:
var arr [3]int=[3]int{1,2,3}
var arr=[3]int{1,2,3}
var arr=[...]int{1,2,3}
var arr=[...]int{1:2,0:1,2:3}
  数组:同一类型元素的组合,数组的地址可以通过&数组名来获取,数组的第一个元素的地址是数组的首地址
  数组的使用步骤:申明数组并开辟空间,给数组元素的值赋值,使用数组
  如果要修改素组内的值,采用引用的办法
  [32]byte     // 长度为32的数组,每个元素为一个字节 [2*N] 
  struct { x, y int32 } // 复杂类型数组 
  [1000]*float64   // 指针数组 
  [3][5]int    // 二维数组
   [2][2][2]float64   // 等同于[2]([2]([2]float64))
   数组是值传递
   package main   
	import "fmt" 

func modify(array [10]int) { array[0] = 10 // 试图修改数组的第一个元素 fmt.Println(“In modify(), array values:”, array)
}
func main() { array := [5]int{1,2,3,4,5} // 定义并初始化一个数组
modify(array) // 传递给一个函数,并试图在函数体内修改这个数组内容
fmt.Println(“In main(), array values:”, array) }
该程序的执行结果为:
In modify(), array values: [10 2 3 4 5]
In main(), array values: [1 2 3 4 5]

5.切片

切片从底层上来说是一个数据结构(struct)
基于myArray的所有元素创建数组切片:mySlice = myArray[:]
基于myArray的前5个元素创建数组切片: mySlice = myArray[:5]
基于myArray的后5个元素创建数组切片: mySlice = myArray[5:]
创建一个初始元素个数为5的数组切片,元素初始值为0: mySlice1 := make([]int, 5)
创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:mySlice2 := make([]int, 5, 10)
直接创建并初始化包含5个元素的数组切片: mySlice3 := []int{1, 2, 3, 4, 5}
添加3个元素:mySlice4=append(mySlice4,1,2,3)
添加一个切片:mySlice=append(mySlice,mySlice4…)
基于数组切片创建数组切片:
oldSlice := []int{1, 2, 3, 4, 5}
newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片,结果1,2,3,4
string的底层是byte数组,可以用切片处理
修改string的方法:将字符串str该为[]byte(str)
Go 编程基础

6map

申明变量:var mymap map [string]int
申明是不需要分配内存的,初始化需要make,分配内存后才能赋值和使用
初始化: mymap:=make(map[string]int)
其中key 通常不能为map,function,slilce来使用,因为无法==
human :=make(map[string]student,3)
human[“no1”]=student{“刘成杰”,“男”}
human[“no2”]=student{“刘成”,“男”}
human[“no3”]=student{“成杰”,“女”}
human[“no4”]=student{“liu成杰”,“女”} //map的扩容方法
fmt.Println(len(human))
容量为4
建立map 的方法
Go 编程基础
Go 编程基础
Go 编程基础
a[faker]=no.1,没有这个key就扩容,有这个key就重新赋值,len()看map 的长度,因为自动扩容,没办法看cap()
删除单个key:delete(heros,“hero1”),直接删除key
删除整个map,遍历整个map,然后单个删除,第二,直接重新定义map
heros:=make(map[string]string)
Go 编程基础
var mymap map[string]string
mymap= make(map[string]string,3)
mymap[“武松”]=“有个不敢干嫂子”
mymap[“武大郎”]="漂亮能干的老婆 "
renyao:=make(map[string]map[string]string)
renyao[“唐僧”]=make(map[string]string)
renyao[“唐僧”][“唐长老”]=“女儿国国王看上"长"老”
renyao[“孙悟空”]=make(map[string]string)
renyao[“孙悟空”][“人妖”]=“一棍打死白骨精”
结果:map[武松:有个漂亮嫂子 武大郎:漂亮能干的老婆 ]
map[唐僧:map[唐长老:女儿国国王看上"长"老] 孙悟空:map[人妖:一棍打死白骨精]]
map切片:

Go 编程基础

7. switch

case,switch 后面是表达式(常亮,变量,有返回值的函数等)
case 后面的表达式需要 :,case后的表达式可以用多个,用 ,隔开
fallthough,在case语句后加一个fallthough(穿透),继续向下执行
break 跳出最近一层for循环
break 后面可以指定标签,跳出标签对应的for循环
Go 编程基础
for 循环一般建议做多两层,最多不不超过3层
contiue和if连用,可以跳过指定循环
Go 编程基础
goto 能够无条件的转移到程序中的指定行,一般不主张使用goto,goto跟随标识符跳转
Go 编程基础
return跳出函数或者方法
return在普通函数直接跳出函数(终止函数),在主函数终止程序

8.函数 包和错误处理

文件的包名通常和文件所在的文件名名字一致,都为小写,函数名通常为大写,这样才能被外部调用
Go 编程基础
调用函数时,会给函数分配一个新的栈空间,每个函数的栈中空间是独立的 ,函数调用完后销毁函数,释放栈

匿名函数

函数等当做参数,传递给函数
Go 编程基础
Go 编程基础
函数参数支持可变参,如果最后一个参数是可变参,需要放到最后
Go 编程基础
init函数在main函数之前被调用完成初始化工作
面试题:如果main.go 和utils.go都含有定义变量,init函数时,执行流程是怎么样的
先执行utils.go的函数,然后init,在然后main(utils.go 放常用方法)
Go 编程基础
Go 编程基础
如果只希望函数执行一次就用匿名函数 ,将匿名函数赋值给全局变量,那么匿名函数对整个程序有效
Go 编程基础Go 编程基础
闭包
Go 编程基础当输出是i的值,闭包递增,完成累加(i在闭包外面)
Go 编程基础当需要打印n的值的时候,闭包保持每次进出都遵循传进来的结果
Go 编程基础
闭包传入的是后面需要返回的匿名函数

defer会压到栈中(多个defer也是这样先入后出),defer最主要用在延迟关闭资源
Go 编程基础
值传递:map,切片,channel,接口!!结构体是值传递,值传递的放在堆上,没有使用的话直接GC回收
变量或者常亮,对一在函数外,若首字母大写对整个程序有效,定义小写则对包有效
new用来分配内存,主要用来分配值类型,如int,float64,sturct …返回的是指针
make:用来分配内存,主要分配引用类型,主要用于切片,map,channel

自定义错误类型:panic(),errors.New()

9.排序和查找

内部排序:数据量较小的情况下,加载到内部储存器排序(冒泡排序,选择试排序,插入是排序)
外部排序: 数据量大,无法加载到内存中,借助外部储存排序(合并排序和直接合并排序法)
冒泡排序:
func bubbleSort(sli []int) {
for i:=0;i<len(sli);i++ {
for j:=i+1;j<len(sli) ; j++ {
if sli[i]<sli[j]{
sli[i],sli[j]=sli[j],sli[i]
}
}
}
}
func main() {
start:=time.Now().UnixNano()
sli:=[]int{5,9,8,3,2,4}

bubbleSort(sli)
end:=time.Now().UnixNano()
fmt.Println(sli,start-end)

}

二分查找:底层依赖数组,有序适合静态数据(没有平凡插入删除的),适合数据较大的数组

10.面向对象

OOP:只有继承,封装,多态的特性
int的零值(默认值)0 string " " bool false 数组 0 指针,切片,map都是nil,没有分配空间
结构体是值传递
结构体的所有字段在内存中是连续的
不同的结构体变量的是独立的互不影响(值传递)
创建结构体变量和访问结构体字段
Go 编程基础
struct 的序列化和反序列化
Go 编程基础
结构体实例后直接调用方法
Go 编程基础
方法不仅可以绑定strct,还可以绑定其他的
封装实现的步骤:
1.将结构体,字段(属性)首*字母小写了,无法导出,其他包无法使用(依靠工厂模式)
2.给结构体提供一个工厂模式的函数,首字母大写,类似一个构造函数
3.提供首字母大写的Set方法(其他函数可以调用的),用于对属性判断并赋值func(var *结构体名)Setxxx(参数列表)(返回值列表)
//假如数据验证的逻辑
var.字段=参数
4.提供首字母大写的Get方法,获取属性的值
fun(var *结构体名 )Getxxx()(返回值){
return var.想要返回的
}
Go 编程基础Go 编程基础Go 编程基础
面向对象继承,能够继承结构体和方法
Go 编程基础
Go 编程基础
可以简化成:
Go 编程基础
当结构体和匿名结构体有相同的字段和方法时,采用就近原则
Go 编程基础
嵌套匿名结构体后,也可以直接创建结构体变量(实例),直接指定各个字段的值
Go 编程基础
Go 编程基础
一个结构体只能有一个同类型的匿名字段

12.接口

interface类型能够定义一种方法,但是不需要实现,interface不能包含任何变量

基本语法Go 编程基础
Go 编程基础
Go 编程基础
接口里的方法都没有方法体,即接口都是没有实现的方法,体现了程序多态,高内聚,低耦合的思想
golang中的接口不需要显示的实现,只要一个变量含有接口中所有的方法,那么这个变量就实现了接口中所有的接口
注意和细节:
接口本身不能创建实例,但是可以指向一个实现了该接口自定义类型的变量(实例)
Go 编程基础
2.接口中所有的方法都没有方法体,即都是没有实现的方法
3.一个自定义的类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口
4.自定义的类型只有实现了该接口,才能将自定义类型的实例(变量)赋给接口类型
5.只要是自定义的数据类型,就可以实现接口,不仅仅是结构体类型
Go 编程基础
Go 编程基础
一个自定义类型可以实现多个接口
Go 编程基础Go 编程基础
7.接口中不能有任何变量
8.一个接口可以继承其他多个接口,如果要实现该接口,但是前提其他接口的方法也全实现
Go 编程基础
Go 编程基础
9.接口的默认类型是指针,如果interface没有初始化就使用,那么会输出nil
10.空接口interface{}没有任何的方法,所以所有的类型都实现了该接口,即我们可以吧任何的值赋给空接口

接口和继承:
Go 编程基础Go 编程基础
继承的价值在于:代码的复用性和可维护性
接口的价值在于:设计,设计好各种规范(方法),让其他自定义类型去实现这些方法
接口比继承更加灵活,继承是(is-a),接口是(like-a),接口能在一定程度上实现代码解耦

多态的特征是通过接口实现的
多态:变量(实例)具有多种形态
Go 编程基础
多态有两种形式:多态参数(上面的computer),多态数组
Go 编程基础
Go 编程基础
类型断言(带检测):
检测不知道的类型的变量(实例)给接口,判断能否正常赋值,不能正常赋值也不能报panic
Go 编程基础