Go

1.声明变量

  1. 1.指定变量类型 (variable)
  2. var i int
  3. 如果未指定默认值 那么默认值为0
  4. 2.自动判断值类型
  5. var i="string";
  6. 3.省略var 初始化声明
  7. hello:="spark"
  8. 多变量声明
  9. 1.指定声明变量的类型 统一类型
  10. var i,k,s,w int
  11. 2.声明不同的类型
  12. var (
  13. i int
  14. str string
  15. b bool
  16. )
  17. !!!在同一个作用域当中 不能对变量进行二次初始化 :变量名=v

2.Go语言常量

  1. const关键词 常量声明语法
  2. 1.单个常量声明方法 显示声明 const 变量名 变量类型=value
  3. const str string ="100"
  4. 2.隐示声明 可省略string 因为会自动推断类型
  5. const str ="100"
  6. const str,str1 int
  7. 3.枚举声明
  8. const (
  9. MAN=1
  10. GIRL=0
  11. )
  12. 4.特殊常量iota const关键词出现时被重置为0 每次出现一次+1可以把iota当作const索引
  13. const (
  14. MAN = iota //0
  15. MAIN //1
  16. _ //2
  17. afer //3
  18. )

3.运算符

  1. //算术运算符
  2. + - * / ++ --
  3. //关系运算符 跟Java中的一致
  4. == != > < >= <=
  5. //逻辑运算符
  6. && || !

4.for循环

  1. //berak关键词 停止当前循环
  2. //goto 跳转到指定的标签
  3. //continue 跳过当前循环
  4. func main() {
  5. //var i="string";
  6. for i:=1; i<=10 ;i++ {
  7. // goto breakHader
  8. if(i==1){
  9. fmt.Println(i)
  10. }else if(i==10){
  11. fmt.Println("执行")
  12. goto breakHader
  13. }else{
  14. if(i==5){
  15. fmt.Println(i)
  16. break;
  17. }
  18. }
  19. }
  20. breakHader:
  21. fmt.Print("Message")
  22. }

5.Go函数

  1. //声明函数
  2. func function_name(param list)(return paramList)
  3. {
  4. //函数体
  5. }
  6. //demo
  7. func GetMaxNum(a ,b int)(int){
  8. //声明一个返回变量
  9. var result int
  10. if(a<b){
  11. result=b;
  12. }else if(b>a){
  13. result=a
  14. }
  15. return result
  16. }
  17. //main函数
  18. //noinspection ALL
  19. func main() {
  20. //var i="string";
  21. var num=GetMaxNum(1,10);
  22. fmt.Print(num)
  23. }
  24. //匿名函数 把一个函数作为方法的返回值
  25. func function_name func()匿名函数返回值//int {
  26. }
  27. func getSequenes() func()int{
  28. var i =0
  29. return func() int{
  30. i++
  31. return i;
  32. }
  33. }
  34. //noinspection ALL
  35. func main() {
  36. sequene := getSequenes()
  37. fmt.Println(sequene())
  38. fmt.Println(sequene())
  39. //var i="string";
  40. //var num=GetMaxNum(1,10);
  41. //fmt.Print(num)
  42. }

6.数组声明

  1. [length]Type
  2. [N]Type{value1, value2, ..., valueN}
  3. [...]Type{value1, value2, ..., valueN} 初始化数组
  4. var 数组名称[] type
  5. //不指定数组长度
  6. var 数组名称=[...]int{1,2,3,4,501}
  1. 语言指针

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 )

  1. <a name="18ac36a1"></a>
  2. #### 8.结构体定义
  3. > Go语言中的基础数据类型可以表示一些事务的基本熟悉,但是当我们想表达一个事务的全部或部分属性时,这时候使用单一基本数据类型就无法满足了。Go语言提供了一种自定义数据类型,struct这种类型称之为结构体。我们可以采用struct来定义自己的类型
  4. ```go
  5. //语法
  6. type 类型名 struct{
  7. filedName type
  8. filedName type
  9. //1.类型名 标识自定义结构体的名称,在同一个包内不能重复
  10. //2.字段名 表示结构体字段名。结构体中的字段名必须唯一
  11. //3.字段类型 表示结构体字段的具体类型
  12. }
  13. //比如 创建一个Person自定义类型,该类型拥有name和age2个字段
  14. type Person struct{
  15. name string
  16. age int
  17. }
  18. //结构体实例化 结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型
  19. var 结构体实例 结构体类型
  20. //1.基本实例化
  21. var person Person
  22. person.name="zhangsan"
  23. person.age=18
  24. //2.匿名结构体
  25. var user struct{name string;age int}
  26. user.name="李四"
  27. user.age=20
  28. //3. 创建指针类型结构体
  29. //采用new关键字对结构体进行实例化,得到的是结构体的地址
  30. var p2=new(Person)
  31. fmt.Println(p2)//&{ 0} 可以看出p2是一个结构指针
  32. //4.取结构体的地址实例化 使用&对结构体进行取地址操作,相当于对该结构体类型进行了一次new实例化操作
  33. var p2=&Person{}
  34. p2.name="张三"
  35. //p2.name="张三"其实在底层是(*p3).name="张三" 这是Go帮我们实现的语法糖
  36. //5.使用键值对初始化 使用键值对对结构体进行初始化时,键对应结构体的字段,值对应字段的初始值
  37. var p4=Person{name: "张三",age: 20}
  38. fmt.Println(p4)//{张三 20}
  39. //使用指针初始化
  40. var p5=&Person{name: "张三",age: 21}
  41. fmt.Println(p5)//&{张三 21}
  42. //6使用值的列表进行初始化
  43. var p6= Person{"张三", 12}
  44. //初始化结构体的时候可以简写,也就是初始化的时候不写键位,直接写值
  45. //使用该初始化操作的时候
  46. //1.必须初始化结构的所有字段
  47. //2.初始值的填充顺序必须与字段在结构体内的声明顺序一致
  48. //3. 该方式不能和键值初始化方式混用

8.1 构造函数
  1. //Go语言的结构体没有构造函数。所以我们可以自己实现。如果结构体比较复杂的话,值拷贝性能会比较大,所以构造函数返回结构的指针类型
  2. func NewPerson(name string, age int) *Person {
  3. return &Person{name, age}
  4. }

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} }

  1. > > <a name="fc5de87c"></a>
  2. #### 什么时候使用指针类型?
  3. >
  4. > - 需要修改接收者中的值
  5. > - 接收者是拷贝代价比较大的对象
  6. > - 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者
  7. > > <a name="0d0ec810"></a>
  8. #### 8.3 结构体的匿名字段
  9. > > 结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就成为匿名字段
  10. > ```go
  11. type Person struct{
  12. string
  13. int
  14. }
  15. func main{
  16. p:=Person{"zk",12}
  17. //匿名字段默认采用类型名作为字段名,结构体要求字段必须唯一,因此一个结构体中同种类型的匿名字段只能有一个
  18. }

8.4 嵌套结构体

一个结构体种可以嵌套包含另一个结构体或结构体指针

  1. type Address struct{
  2. Province string
  3. City string
  4. }
  5. type User struct{
  6. Name string
  7. Address Address
  8. }
  9. func main(){
  10. user1 := User{
  11. Name: "张三",
  12. Address: Address{
  13. Province: "浙江",
  14. City: "杭州",
  15. },
  16. }
  17. fmt.Println(user1)//{张三 20 {浙江 杭州}}
  18. }

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) //对于匿名结构体内部可能存在相同的字段名,这个时候 应该为了避免歧义需要指定具体的内嵌结构体的字段 }

  1. > > <a name="8526f930"></a>
  2. #### 8.6 结构体的"继承"
  3. > > Go语言中使用结构体也就可以实现其他变成语言中面向对象的继承
  4. > ```go
  5. type Animal struct {
  6. name string
  7. }
  8. func (a *Animal) move() {
  9. fmt.Println(a.name + "移动")
  10. }
  11. type Dog struct {
  12. Feet int
  13. *Animal
  14. }
  15. func (d *Dog) wang() {
  16. fmt.Println(d.name + "WWWW")
  17. }
  18. func main() {
  19. //继承
  20. dog := Dog{Feet: 12,
  21. Animal: &Animal{name: "旺财"}}
  22. dog.move()
  23. dog.wang()
  24. }

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) } }

  1. > > <a name="5df4b6af"></a>
  2. #### 8.10 结构体标签(Tag)
  3. > > Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来
  4. > Tag在机构提字段的后方定义,由一对反引号包裹起来,具体的格式如下:
  5. >

key:"value1" key2:"value2"

  1. > 结构体标签由一个或多个键值对组成。键与值使用冒号分割,值用双引号括起来。键值对之间使用一个空格分隔。
  2. > ```go
  3. type Student struct {
  4. Name string `json:"name"`
  5. Id int //json序列化默认使用字段名作为key
  6. sex string //私有不能被json包访问
  7. }
  8. func main() {
  9. stu := &Student{Name: "张三", Id: 1, sex: "男"}
  10. json, _ := json.Marshal(stu)
  11. fmt.Println(string(json))//{"name":"张三","Id":1}
  12. }

8.11 map有序输出

  1. func main() {
  2. //创建一个int键值map数组
  3. maps := make(map[int]string, 10)
  4. maps[1] = "A"
  5. maps[2] = "B"
  6. maps[3] = "C"
  7. maps[4] = "D"
  8. //创建一个存放maps的key值的数组
  9. var sli []int
  10. //循环把所有的key放进map当中
  11. for i, _ := range maps {
  12. sli = append(sli, i)
  13. }
  14. //排序
  15. sort.Ints(sli)
  16. //循环输出
  17. for i := 0; i < len(maps); i++ {
  18. fmt.Println(maps[sli[i]])
  19. }
  20. }

9.切片

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片和数据对应的是同一份数据,切片只是数组的一个引用,如果原数组的数据发生变化,那么会连带着切片中的数据一起变化。切片和数组的创建方式区别

  1. [...]T{} //数组
  2. []T{} //切片

新获得的切片跟源切片底层对应的数组都是同一个,所以对其中一个切片元素的修改也会影响到另外一个

  1. 声明切片语法
  2. make([]type, length, capacity)
  3. make([]type, length)
  4. []type{}
  5. []type{value1, value2,..., valueN}
  6. s[n] 切片s中索引位置为n的项
  7. s[n:m] 从切片s的索引位置nm-1处所获得的切片
  8. s[n:] 从切片s的索引位置到len(s)-1处所获得的切片
  9. s[:m] 从切片s的索引位置0m-1处所获得的切片
  10. s[:] 从切片s的索引位置0len(s)-1处获得的切片
  11. var identifier []type
  12. 切片初始化
  13. s:=[]int{1,2,3}
  14. /* 创建切片 长度为4 最长长度可以达到4*/
  15. slice := make([]int, 2, 4)
  16. append_slice := []int{1, 2}
  17. fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
  18. //追加2个元素 地址未改变
  19. slice = append(slice, append_slice...)
  20. fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
  21. //继续追加 地址改变
  22. slice = append(slice, 10, 20)
  23. fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
  24. slice = append(slice, 30, 40, 50)
  25. fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
  26. slice addr:0xc000052140 len:2 cap:4 slice:[0 0]
  27. slice addr:0xc000052140 len:4 cap:4 slice:[0 0 1 2]
  28. slice addr:0xc00006c140 len:6 cap:8 slice:[0 0 1 2 10 20]
  29. slice addr:0xc00008a000 len:9 cap:16 slice:[0 0 1 2 10 20 30 40 50]

10.创建Map集合

  1. //声明map的方式
  2. var hashMap=make(map[keyType]valueType);
  3. var hashMap=make(map[string]string)
  4. hashMap["Lucy"]="张三"
  5. hashMap["Ad"]="Nike"
  6. for k, v := range hashMap {
  7. fmt.Println(k+"\t"+v)
  8. }
  9. //删除函数
  10. delete(hashMap,"Lucy")
  11. for k, v := range hashMap {
  12. fmt.Println(k+"\t"+v)
  13. }

11.类型转换

  1. type_name(exp)
  2. var name=12
  3. var str=string(12)
  4. //string转int
  5. nb,_=strconv.Atio(str)
  6. //string转 int 64
  7. in64, err := strconv.ParseInt(string, 10, 64)
  8. //int转换成string
  9. string := strconv.Itoa(int)
  10. //int64转换成 string
  11. string := strconv.FormatInt(int64,10)

12.接口定义 实现

  1. //定义一个say的接口
  2. type Say interface {
  3. sayHelloWorld();
  4. }
  5. type sayHello struct {
  6. }
  7. type saySpeak struct {
  8. }
  9. //实现类
  10. func (say sayHello) sayHelloWorld() {
  11. fmt.Println("helloworld")
  12. }
  13. //实现类
  14. func ( saySpeak saySpeak)sayHelloWorld(){
  15. fmt.Println("Nice")
  16. }
  17. func main() {
  18. var say Say
  19. say=new(sayHello)
  20. say.sayHelloWorld();
  21. say=new(saySpeak);
  22. say.sayHelloWorld();
  23. }

13 异常情况

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. // 定义一个 DivideError 结构
  6. type DivideError struct {
  7. dividee int
  8. divider int
  9. }
  10. // 实现 `error` 接口
  11. func (de *DivideError) Error() string {
  12. strFormat := `
  13. Cannot proceed, the divider is zero.
  14. dividee: %d
  15. divider: 0
  16. `
  17. return fmt.Sprintf(strFormat, de.dividee)
  18. }
  19. // 定义 `int` 类型除法运算的函数
  20. func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
  21. if varDivider == 0 {
  22. dData := DivideError{
  23. dividee: varDividee,
  24. divider: varDivider,
  25. }
  26. errorMsg = dData.Error()
  27. return
  28. } else {
  29. return varDividee / varDivider, ""
  30. }
  31. }
  32. func main() {
  33. // 正常情况
  34. if result, errorMsg := Divide(100, 10); errorMsg == "" {
  35. fmt.Println("100/10 = ", result)
  36. }
  37. // 当被除数为零的时候会返回错误信息
  38. if _, errorMsg := Divide(100, 0); errorMsg != "" {
  39. fmt.Println("errorMsg is: ", errorMsg)
  40. }
  41. }