golang学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaobafacai/article/details/77876753

直接跳过没有看的

  1. 入门 -> 命令行参数 之后的所有行

Go基础

命令

  1. go run one.py -> 编译并运行
  2. go build one.py -> 编译成可执行文件

变量

  1. 大写字母开头的变量是可导出的,是公用变量
  2. 小写字母开头的是不可导出的,是私有变量
  3. 大写字母开头的函数也是一样,相当于class里面带public关键词的公有函数
  4. 小写字母开头的函数就相当于class里面带private关键词的私有函数
  5. 全局变量(变量组只能在全局环境下使用)

    var (
    name = "gopher",
    name1 = 1,
    name2 = "2"
    )
  6. 一般类型声明

    type (
    newType int
    type1 float32
    type2 string
    type3 byte
    )
  7. 自定义类型

    type(
    byte int8
    name int32
    文本 string
    )
  8. 变量的类型转换
    • Go中不存在隐式转换,所有类型转换必须显式声明
    • 转换只能发生在两种相互兼容的类型之间
    • 类型转换的格式:var a float32 = 1.1 -> b := int(a),var a int = 65 -> string(a) -> A
    • 数字类型转换成字符串 -> import strconv -> b:=strconv.Itoa(a) -> a=strconv.Atoi(b)
    • string(byte) -> 转换成字符串
  9. Print用双引号,反引号相当于Python里面的“`。单引号->rune类型

常量

  1. 在定义常量组时,如果不提供初始值,则表示将使用上一行的表达式

    const(
    a = 1
    b
    c
    )
  2. 枚举值 iota ,是常量的计数器,从0开始,组中每定义一个常量自动递增1,每遇到一个const,iota就会重置为0。

语句

  1. switch

    func main()  {
    a := 1
    switch a {
    case a>=0:
        fmt.Println("a=0")
        fallthrough //满足这个条件之后继续向下寻找
    case a>=1:
        fmt.Println("a=1")
    default:
        fmt.Println("None")
    
    }
    }
  2. for,goto,break

    func main(){
    LABEL1:
    for i:=0;i<10;i++{
    if i>3{
    goto LABEL1 // 跳到LABEL标签所在的位置
    break LABEL1 // 跳出当前循环至LABEL那一级,
    }
    }
    }

指针

  1. Go语言虽然保留了指针,但与其他语言不同的是,在Go当中不支持指针运算以及 -> 运算符,而直接采用.操作符来操作指针目标对象的成员
  2. 操作符&取变量地址,使用*通过指针间接访问目标对象
  3. 默认值为nil而非NULL

数组

  1. 具有相同唯一类型的一组已编号且长度固定的数据项序列(数组的长度必须是常量表达式)
  2. 数组的长度是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数据类型
  3. 数组之间的赋值是值的赋值,也就是当把数组当作参数传入函数的时候 ,传入的其实是该数组的副本,而不是它的指针
  4. 默认情况下,数组的每个元素都被初始化成元素对应类型的零值.对于数字类型来说就是0。
    var r [3]int = [3]int{1,2} -> r -> [1,2,0]
1. var names [3]string // 默认初始化方式
2. q:= [...]int{1,2,3} // 如果数组的长度位置出现"...",则表示数组的长度是根据初始化值的个数计算
3. r := [...]int{99:-1} // {99:-1} -> 共100项,前99都是0,最后一个是-1
4. r := [...]int{0:1,1:2,2:3}
5. 指针数组 -> 
    ```
        x,y := 1,2
        a := [...]*int{&x,&y}
        fmt.Println(a)
    ```
二维数组
  1. doubleArray := [2][4]int{[4]int{1,2,3,4},[4]int{5,6,7,8}} 该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素
  2. easyArray := [2][4]int{{1,2,3,4},{5,6,7,8}} 如果内部元素和外部的一样,那么上面的声明可以简化,直接忽略内部的类型

Slice

  1. Slice代表变长的序列,序列中每个元素都有相同的类型。语法和数组很像,只是没有固定长度。
  2. 引用类型 -> “动态数组”
  3. 从概念上来说,slice像一个结构体,这个结构体包含了三个元素:一个指针,指向数组中slice指定的开始位置;长度,即slice的长度;最大长度,也就是slice开始位置到数组的最后位置的参数
  4. 使用len()获取长度,cap()获取容量
  5. 可以直接创建或者从底层数组获取生成
  6. 索引不可以超过被slice的切片的容量cap()值
  1. 和声明array一样,只是少了长度 var fslice []int。声明两个slice -> var aSlice,bSlice []byte
  2. 一般使用make()函数来创建切片 make([]T,len,cap),其中cap可以省略,则和len的值相同
    make([]int,10,20)
  3. append() 返回一个新的切片。如果最终长度未亿加到sliice的容量则返回原始slice,如果超过追加到的sliice的容量则重新分配数组并拷贝原始数据

        a := []int{1,2,3,4,5}
        s1 := a[2:5]
        s2 := a[1:3]
        fmt.Println(s1,s2)
    
        // s2 = append(s2,7,8,9)  // 总长度已经超过cap,所以是一块新的内存区域,没有对原切片进行修改
        // s2 = append(s2,7,8) // 总长度没有超过cap,所以对原切片进行了修改
        fmt.Println(a)
        fmt.Println(s1)
  4. copy(s1,s2) s1是母体,s2是被复制的,把s2从s1的头部开始覆盖
map
  1. 声明map

    <ol><li>var m map[int]string; m=map[int]string{} -> 完成初始化 // [int]代表key的类型,string代表value的类型</li>
    <li>m := make(map[int]string)
  • 删除键值

    delete(m,1) // m是map对象,1是键名
  • 判断键存在不存在

    a,ok := m[2][1] // 此时ok=false(如果该位置元素不存在)
  • 迭代

    for k,v := range m{}
  • 排序

    import sort
    sort.Ints(s)
  • 初始值
    1. int -> 0
    2. string -> “”
    3. boolean-> false
    4. slice,map,chan,func -> nil
    5. array,struct -> 每个元素或字段该类型的零值
    6. 一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化 var f,err = os.Open(name)

    _ -> 废弃值(空标识符),用于任何语法需要变量名但程序逻辑不需要的时候
    range -> 每次循环迭代,range产生一对值,索引以及在该索引处的元素值。
    strings.Join -> 连接,Join(可迭代对象,连接符)

    格式化

    1. %g -> 数字

    字符串

    1. 用一对双引号或者反引号括起来定义

    2. 反括号引起来的是RAW格式

    new和make

    1. new会分配结构空间,并初始化为清空为零,不进一步初始化,new之后需要一个指针指向这个结构。(返回一个指向数组的指针)

      p := new([10]int)
      fmt.Println(p)
      
      --------
      &[0 0 0 0 0 0 0 0 0 0]
    2. make会分配结构空间及其附属空间,并完成其间的指针初始化,make返回这个结构空间,不另外分配一个指针

    函数

    1. Go函数不支持嵌套、重载和默认参数
      仅支持:
      1. 无需声明原型
      2. 不定长度变参
      3. 多返回值
      4. 命名返回值参数
      5. 匿名函数
      6. 闭包
      7. 函数可以作为一种类型使用
      8. func A(a, b, c int)(int,int,string){}
      9. 命名返回值

        func A()(a,b,c int){ //此时a,b,c已经声明
        a,b,c = 1,2,3
        return
        }
      10. 不定长参数

      func A(a ...int){
          fmt.PrintlnI(a)  // a是一个slice //值拷贝
      }

      在不定长参数里面,如果要放其他参数,需要放在不定长参数前面,func A(b string,a …int){}
      如果直接把一个slice扔进来,那slice本身是引用传参
      int string 等传参是值传参,如果要进行引用传参,可以传指针进来,通过指针间接修改原值
      “`
      func main(){
      a := 1
      A(&a)
      fmt.Println(a)
      }

      func A(a *int){
          *a = 2
          fmt.Println(*a)
      }
      ```
      
    2. 闭包

          func main() {
              f := closure(10)
              fmt.Println(f(1))
              fmt.Println(f(2))
          }
      
          func closure(x int) func(int) int {
              return func(y int) int {
                  return x + y
              }
          }
      
    3. defer
      执行方式类似其他语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
      即使函数发生严重错误也会执行
      支持匿名函数的调用
      常用于资源清理、文件关闭、解锁以及记录时间等操作
      通过与匿名函数配合可在return之后修改函数计算结果
      如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址
      Go没有异常机制,但有panic/recover模式来处理错误
      Panic可以在任何地方引发,但recover只有在defer调用的函数中有效

    结构体struct

    1. Go中的struct与C中的struct非常相似,并且Go没有class
    2. 使用type<Name>struct{}定义结构,名称遵循可见性规则
    3. 支持指向自身的指针类型成员
    4. 支持匿名结构,可用作成员或定义成员变量
    5. 匿名结构也可以用于map的值
    6. 可以使用字面值对结构进行初始化
    7. 允许直接通过指针来读写结构成员
    8. 相同类型的成员可进行直接拷贝赋值
    9. 支持 ==!=比较运算符,但不支持><
    10. 支持匿名字段,本质上是定义了以某个类型名为名称的字段
    11. 嵌入结构作为匿名字段看起来像继承,但不是继承
    12. 可以使用匿名字段指针
    13. 在函数,属于值拷贝,如果要改原值,需要修改指针。

      type person struct{
      name string
      age int
      }
      func A(per *person){
      per.age = 13
      }

      如果需要改的次数过多,需要先取指针(推荐)
      “`
      a := &person{
      name :”Joe”,
      age:19,
      }
      a.name = “xiaoming” //直接操作指针就可以
        A(a)
        B(a)
    
        func A(per *person){
            per.age = 13
        }
    
        func B(per *person){
            per.age = 15
        }
    
    ```
    
    1. 基本使用

      type person struct{
      Name string
      Age int
      }
      func main(){
      a:= person{
      Name:"Joe"
      }
      a.Age = 19
      fmt.Println(a)
      }
    2. 匿名结构

      func main(){
          // a := struct{
          a := &struct{
              name string
              age int
          }{
              name:"xiaoming",
              age:19,
          }
      
          fmt.Println(a)
      }
    3. 嵌套匿名结构体

      type person struct{
          name string
          age int
          contact struct{
              phone, city string
          }
      }
      
      func main(){
          a := person{name:"joe",age:19}
          a.contact.phone = "122332"
          a.contact.city = "beijing"
          fmt.Println(a)
      }
    4. 匿名字段

      type person struct{
      string
      int
      }
      func main(){
      a := person{"joe",19}
      fmt.Println(a)
      }
    5. 继承

      type human struct{
          sex int
      }
      type teacher struct{
          human
          name string
          age int
      }
      type student struct{
          human 
          name string
          age int
      }
      
      func main(){
          a := teacher{name:"han",age:12,human:human{sex:1}}
          b := student{name:"zhang",age:19,human:human{sex:0}}
          a.name = "joe"
          a.age = 13
          a.sex = 100
          fmt.Println(a)
      }
      
    6. 内外层有同名属性

      type person struct{
          name string
          age int
      }
      type student struct{
          person
          name string
          age int
      }
      
      func main(){
          a := student{name:"zhangsan",age:12,person:person{name:"lisi",age:20}}
          fmt.Println(a.name)  // zhangsan
          fmt.Println(a.person.name)  //lisi
      }
      
      // 嵌入级别大于1个的时候 ,不允许有同名属性,否则编译报错

    方法

    1. Go中虽然没有class,但依旧有method
    2. 通过显示说明receiver来实现与某个类型的组合
    3. 只能为同一个包中的类型定义方法
    4. Receiver可以是类型的值或指针
    5. 不存在方法重载
    6. 可以使用值或指针来调用方法,编译器会自动完成转换
    7. 从某种意义上来说,方法是函数的语法糖,因为receiver其实就是方法所接收的第1个参数
    8. 如果外部结构和嵌入结构存在同名方法,则优先调用外部结构的方法
    9. 类型别名不会拥有底层类型所附带的方法
    10. 方法可以调用结构中的非公开字段
    1. 使用

      type person struct {
          name string
          sex int
      }
      func (p person)sayHello(){   //(p是参数,person是接收者的类型)
          fmt.Println("我是person")
      }
      
      func main()  {
          a := person{}
          a.sayHello()
      }
    2. 方法里面改变结构体的属性 -> 传递指针

      type A struct{
          name string
      }
      func main(){
          a := A{}
          a.Print()
          fmt.Println(a.name)
      }
      
      func(a *A)Print(){
          a.name = "aa"
          fmt.Println("A")
      }
    3. 底层类型的结构定制(只有当前包中有效)

      type TZ int
      func main(){
          var a TZ
          a.Print()
      }
      
      func (a *TZ)Print(){
          fmt.Println("TZ")
      }
    4. method expression -> 直接通过类型调用,而不用通过变量来调用

      type TZ int
      func main(){
          var a TZ
          a.Print()  // method value 通过变量来调用方法
          (*TZ).Print(&a)  // (*TZ)是receiver,&a是变量
      }
      
      func (a *TZ)Print(){
          fmt.Println("TZ")
      }
    5. method冲突,和struct一样
    6. 通过method修改变量的值

      type TZ int
      func main(){
      var a TZ
      fmt.Println(a)
      a.AutoAdd()
      fmt.Println(a)
      }
      func (tz *TZ)AutoAdd(){
      *tz += 100
      }

    接口interface

    1. 接口是一个或多个方法签名的集合
    2. 只要某个类型拥有该接口的所有方法签名,就算实现该接口,无需显式声明实现了哪个接口,这称为Structural Typing
    3. 接口只有方法声明,没有实现,没有数据字段
    4. 接口可以匿名嵌入其他接口,或嵌入到结构中
    5. 将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针
    6. 只有当接口存储的类型和对象都为nil时,接口才等于nil
    7. 接口调用不会做receiver的自动转换
    8. 接口同样支持匿名字段方法
    9. 接口也可实现类似OOP中的多态
    10. 空接口可以作为任何类型数据的容器
    阅读更多
    想对作者说点什么?

    博主推荐

    换一批

    没有更多推荐了,返回首页