Go
1.声明变量
1.指定变量类型 (variable)var i int如果未指定默认值 那么默认值为02.自动判断值类型var i="string";3.省略var 初始化声明hello:="spark"多变量声明1.指定声明变量的类型 统一类型var i,k,s,w int2.声明不同的类型var (i intstr stringb bool)!!!在同一个作用域当中 不能对变量进行二次初始化 :变量名=v
2.Go语言常量
const关键词 常量声明语法1.单个常量声明方法 显示声明 const 变量名 变量类型=valueconst str string ="100"2.隐示声明 可省略string 因为会自动推断类型const str ="100"const str,str1 int3.枚举声明const (MAN=1GIRL=0)4.特殊常量iota 在const关键词出现时被重置为0 每次出现一次+1可以把iota当作const索引const (MAN = iota //0MAIN //1_ //2afer //3)
3.运算符
//算术运算符+ - * / ++ --//关系运算符 跟Java中的一致== != > < >= <=//逻辑运算符&& || !
4.for循环
//berak关键词 停止当前循环//goto 跳转到指定的标签//continue 跳过当前循环func main() {//var i="string";for i:=1; i<=10 ;i++ {// goto breakHaderif(i==1){fmt.Println(i)}else if(i==10){fmt.Println("执行")goto breakHader}else{if(i==5){fmt.Println(i)break;}}}breakHader:fmt.Print("Message")}
5.Go函数
//声明函数func function_name(param list)(return paramList){//函数体}//demofunc GetMaxNum(a ,b int)(int){//声明一个返回变量var result intif(a<b){result=b;}else if(b>a){result=a}return result}//main函数//noinspection ALLfunc main() {//var i="string";var num=GetMaxNum(1,10);fmt.Print(num)}//匿名函数 把一个函数作为方法的返回值func function_name func()匿名函数返回值//int {}func getSequenes() func()int{var i =0return func() int{i++return i;}}//noinspection ALLfunc main() {sequene := getSequenes()fmt.Println(sequene())fmt.Println(sequene())//var i="string";//var num=GetMaxNum(1,10);//fmt.Print(num)}
6.数组声明
[length]Type[N]Type{value1, value2, ..., valueN}[...]Type{value1, value2, ..., valueN} 初始化数组var 数组名称[] type//不指定数组长度var 数组名称=[...]int{1,2,3,4,501}
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。指针接受的是一个变量的内存地址 如果直接赋值会报错
访问指针中的值 采用 *指针名称
一个指针变量指向了一个值的内存地址。```go //输出变量地址 var n [10]int / n 是一个长度为 10 的数组 / n[0]=100 fmt.Printf(“变量的地址: %x\n”, &n[0] ) var a=10 //声明指针变量 var i int //存储 &a的地址 i=&a fmt.Printf(“a 变量的地址是: %x\n”, &a ) / 指针变量的存储地址 */ fmt.Printf(“ip 变量储存的指针地址: %x\n”, i )
/ 使用指针访问值 / fmt.Printf(“ip 变量的值: %d\n”, i )
<a name="18ac36a1"></a>#### 8.结构体定义> Go语言中的基础数据类型可以表示一些事务的基本熟悉,但是当我们想表达一个事务的全部或部分属性时,这时候使用单一基本数据类型就无法满足了。Go语言提供了一种自定义数据类型,struct这种类型称之为结构体。我们可以采用struct来定义自己的类型```go//语法type 类型名 struct{filedName typefiledName type//1.类型名 标识自定义结构体的名称,在同一个包内不能重复//2.字段名 表示结构体字段名。结构体中的字段名必须唯一//3.字段类型 表示结构体字段的具体类型}//比如 创建一个Person自定义类型,该类型拥有name和age2个字段type Person struct{name stringage int}//结构体实例化 结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型var 结构体实例 结构体类型//1.基本实例化var person Personperson.name="zhangsan"person.age=18//2.匿名结构体var user struct{name string;age int}user.name="李四"user.age=20//3. 创建指针类型结构体//采用new关键字对结构体进行实例化,得到的是结构体的地址var p2=new(Person)fmt.Println(p2)//&{ 0} 可以看出p2是一个结构指针//4.取结构体的地址实例化 使用&对结构体进行取地址操作,相当于对该结构体类型进行了一次new实例化操作var p2=&Person{}p2.name="张三"//p2.name="张三"其实在底层是(*p3).name="张三" 这是Go帮我们实现的语法糖//5.使用键值对初始化 使用键值对对结构体进行初始化时,键对应结构体的字段,值对应字段的初始值var p4=Person{name: "张三",age: 20}fmt.Println(p4)//{张三 20}//使用指针初始化var p5=&Person{name: "张三",age: 21}fmt.Println(p5)//&{张三 21}//6使用值的列表进行初始化var p6= Person{"张三", 12}//初始化结构体的时候可以简写,也就是初始化的时候不写键位,直接写值//使用该初始化操作的时候//1.必须初始化结构的所有字段//2.初始值的填充顺序必须与字段在结构体内的声明顺序一致//3. 该方式不能和键值初始化方式混用
8.1 构造函数
//Go语言的结构体没有构造函数。所以我们可以自己实现。如果结构体比较复杂的话,值拷贝性能会比较大,所以构造函数返回结构的指针类型func NewPerson(name string, age int) *Person {return &Person{name, age}}8.2 方法和接收者
Go语言中的方法是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Reveiver)。接收者的概念类似于其他语言中的this或者self
```go func(接收者变量 接收者类型)方法名(参数列表)(返回参数){ 1.接收者变量:接收者中的参数变量命名时,官方建议使用接收者类型名的第一个小写字母。 2.接收者类型: 接收者类型和参数类似,可以是指针类型和非指针类型 3.方法名、参数列表、返回参数:具体格式与函数定义相同 } /Person 结构体 type Person struct { name string age int8 }
//NewPerson 构造函数 func NewPerson(name string, age int8) *Person { return &Person{ name: name, age: age, } }
//Dream Person做梦的方法 func (p Person) Dream() { fmt.Printf(“%s的梦想是学好Go语言!\n”, p.name) }
func main() { p1 := NewPerson(“测试”, 25) p1.Dream() } //方法与函数的区别是 函数不属于任何类型,方法属于特定的类型 //方法的接收者类型 可以是指针 也可以不是指针 唯一的区别如下 //Dream Person做梦的方法 func (p Person) Dream() { p.name = “张三” } func (p *Person) Dreams() { p.name = “李四” } func main() { var p1 = new(Person) p1.name = “zs” p1.Dream() fmt.Println(p1) p1.Dreams() fmt.Println(p1) //输出结果 变量接收者是结构体变量的 无法改变接收者的值 // &{zs 0} //指针接收者可以修改接收者内部的值 //&{李四 0} }
> > <a name="fc5de87c"></a>#### 什么时候使用指针类型?>> - 需要修改接收者中的值> - 接收者是拷贝代价比较大的对象> - 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者> > <a name="0d0ec810"></a>#### 8.3 结构体的匿名字段> > 结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就成为匿名字段> ```gotype Person struct{stringint}func main{p:=Person{"zk",12}//匿名字段默认采用类型名作为字段名,结构体要求字段必须唯一,因此一个结构体中同种类型的匿名字段只能有一个}
8.4 嵌套结构体
一个结构体种可以嵌套包含另一个结构体或结构体指针
type Address struct{Province stringCity string}type User struct{Name stringAddress Address}func main(){user1 := User{Name: "张三",Address: Address{Province: "浙江",City: "杭州",},}fmt.Println(user1)//{张三 20 {浙江 杭州}}}8.5 嵌套匿名结构体
```go type Address struct{ Province string City string createTime string } type User struct{ Name string Gender string Address //匿名结构体 Email } type Email struct{ Account string createTime string }
func main() { user1 := User{ Name: “张三”, Gender: “男”, Address:Address{ Province: “浙江”, City: “杭州”, }, } fmt.Println(user1.City)//直接访问匿名结构体的字段名 fmt.Println(user1.Province) //对于匿名结构体内部可能存在相同的字段名,这个时候 应该为了避免歧义需要指定具体的内嵌结构体的字段 }
> > <a name="8526f930"></a>#### 8.6 结构体的"继承"> > Go语言中使用结构体也就可以实现其他变成语言中面向对象的继承> ```gotype Animal struct {name string}func (a *Animal) move() {fmt.Println(a.name + "移动")}type Dog struct {Feet int*Animal}func (d *Dog) wang() {fmt.Println(d.name + "WWWW")}func main() {//继承dog := Dog{Feet: 12,Animal: &Animal{name: "旺财"}}dog.move()dog.wang()}
8.7 结构体字体地可见性
结构体中字段大写开头表示可以公开访问,小写表示私有(仅在定义当前结构体的包中可访问)
8.9 结构体与JSON序列化
JSON是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON键值对是用来保存JS对象的一种方式,键/值对组合中的键名写在前面并用双引号””包裹,使用冒号分隔,然后紧接着值;多个键值之间使用英文,分隔
```go type Student struct { No int //学号 Name string //学生名称 }
type Class struct { ClassName string //班级名称你 Students []Student } //如果有嵌套结构体在内 我们打印外层的结构体可以正常输出 可视化值,但是嵌套中的值输出的都是一串地址 所以我们可以进行重写对应的结构体的String方法 自定义输出效果 func (c Student) String() string { return “{Name:” + c.Name + “ “ + “No:” + strconv.Itoa(c.No) + “}” } func main() { class := &Class{ ClassName: “三年级二班”, Students: make([]*Student, 0, 20)} for i := 0; i < 100; i++ { stu := &Student{ Name: fmt.Sprintf(“stu%02d”, i), No: i, } //追加 class.Students = append(class.Students, stu) } //序列化json data, _ := json.Marshal(class) fmt.Println(data) fmt.Printf(“json:%s\n”, data) //json.Marshal默认返回的是一个byte结构 //[123 34 67 108 97 115 115 78 97 109 101 34 58 34 228 184 137 229 185 180….] //json:{“ClassName”:”三年级二班”,”Students”:[{“No”:0,”Name”:”stu00”},{“No”:1,”Name”:”stu01”},{“No”:2,”Name”:”stu02”},{“No”:3,”Name”:”stu03”},{“No”:4,”Name”:”stu04”},{“No”:5,”Name”:”stu05”}]} //json字符串转换称json str := “{\”ClassName\”:\”三年级二班\”,\”Students\”:[{\”No\”:0,\”Name\”:\”stu00\”},{\”No\”:1,\”Name\”:\”stu01\”},{\”No\”:2,\”Name\”:\”stu02\”},{\”No\”:3,\”Name\”:\”stu03\”},{\”No\”:4,\”Name\”:\”stu04\”},{\”No\”:5,\”Name\”:\”stu05\”},{\”No\”:6,\”Name\”:\”stu06\”}]}” //初始化Class c := &Class{} err := json.Unmarshal([]byte(str), c) if err == nil { fmt.Println(c) } }
> > <a name="5df4b6af"></a>#### 8.10 结构体标签(Tag)> > Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来> Tag在机构提字段的后方定义,由一对反引号包裹起来,具体的格式如下:>
key:"value1" key2:"value2"
> 结构体标签由一个或多个键值对组成。键与值使用冒号分割,值用双引号括起来。键值对之间使用一个空格分隔。> ```gotype Student struct {Name string `json:"name"`Id int //json序列化默认使用字段名作为keysex string //私有不能被json包访问}func main() {stu := &Student{Name: "张三", Id: 1, sex: "男"}json, _ := json.Marshal(stu)fmt.Println(string(json))//{"name":"张三","Id":1}}
8.11 map有序输出
func main() {//创建一个int键值map数组maps := make(map[int]string, 10)maps[1] = "A"maps[2] = "B"maps[3] = "C"maps[4] = "D"//创建一个存放maps的key值的数组var sli []int//循环把所有的key放进map当中for i, _ := range maps {sli = append(sli, i)}//排序sort.Ints(sli)//循环输出for i := 0; i < len(maps); i++ {fmt.Println(maps[sli[i]])}}
9.切片
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片和数据对应的是同一份数据,切片只是数组的一个引用,如果原数组的数据发生变化,那么会连带着切片中的数据一起变化。切片和数组的创建方式区别
[...]T{} //数组[]T{} //切片
新获得的切片跟源切片底层对应的数组都是同一个,所以对其中一个切片元素的修改也会影响到另外一个
声明切片语法make([]type, length, capacity)make([]type, length)[]type{}[]type{value1, value2,..., valueN}s[n] 切片s中索引位置为n的项s[n:m] 从切片s的索引位置n到m-1处所获得的切片s[n:] 从切片s的索引位置到len(s)-1处所获得的切片s[:m] 从切片s的索引位置0到m-1处所获得的切片s[:] 从切片s的索引位置0到len(s)-1处获得的切片var identifier []type切片初始化s:=[]int{1,2,3}/* 创建切片 长度为4 最长长度可以达到4*/slice := make([]int, 2, 4)append_slice := []int{1, 2}fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)//追加2个元素 地址未改变slice = append(slice, append_slice...)fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)//继续追加 地址改变slice = append(slice, 10, 20)fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)slice = append(slice, 30, 40, 50)fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)slice addr:0xc000052140 len:2 cap:4 slice:[0 0]slice addr:0xc000052140 len:4 cap:4 slice:[0 0 1 2]slice addr:0xc00006c140 len:6 cap:8 slice:[0 0 1 2 10 20]slice addr:0xc00008a000 len:9 cap:16 slice:[0 0 1 2 10 20 30 40 50]
10.创建Map集合
//声明map的方式var hashMap=make(map[keyType]valueType);var hashMap=make(map[string]string)hashMap["Lucy"]="张三"hashMap["Ad"]="Nike"for k, v := range hashMap {fmt.Println(k+"\t"+v)}//删除函数delete(hashMap,"Lucy")for k, v := range hashMap {fmt.Println(k+"\t"+v)}
11.类型转换
type_name(exp)var name=12var str=string(12)//string转intnb,_=strconv.Atio(str)//string转 int 64in64, err := strconv.ParseInt(string, 10, 64)//int转换成stringstring := strconv.Itoa(int)//int64转换成 stringstring := strconv.FormatInt(int64,10)
12.接口定义 实现
//定义一个say的接口type Say interface {sayHelloWorld();}type sayHello struct {}type saySpeak struct {}//实现类func (say sayHello) sayHelloWorld() {fmt.Println("helloworld")}//实现类func ( saySpeak saySpeak)sayHelloWorld(){fmt.Println("Nice")}func main() {var say Saysay=new(sayHello)say.sayHelloWorld();say=new(saySpeak);say.sayHelloWorld();}
13 异常情况
package mainimport ("fmt")// 定义一个 DivideError 结构type DivideError struct {dividee intdivider int}// 实现 `error` 接口func (de *DivideError) Error() string {strFormat := `Cannot proceed, the divider is zero.dividee: %ddivider: 0`return fmt.Sprintf(strFormat, de.dividee)}// 定义 `int` 类型除法运算的函数func Divide(varDividee int, varDivider int) (result int, errorMsg string) {if varDivider == 0 {dData := DivideError{dividee: varDividee,divider: varDivider,}errorMsg = dData.Error()return} else {return varDividee / varDivider, ""}}func main() {// 正常情况if result, errorMsg := Divide(100, 10); errorMsg == "" {fmt.Println("100/10 = ", result)}// 当被除数为零的时候会返回错误信息if _, errorMsg := Divide(100, 0); errorMsg != "" {fmt.Println("errorMsg is: ", errorMsg)}}
