GO_基础1

一、环境准备

参考:https://www.cainiaojc.com/golang/go-environment-install.html

  • Vscode环境配置

    • 插件安装

      • go插件:https://marketplace.visualstudio.com/items?itemName=golang.Go
      • Code Debugger插件:https://marketplace.visualstudio.com/items?itemName=wowbox.code-debuger
    • 环境变量设置:

      • GOROOT:

GoROOT环境变量通常指向Go的安装位置。这个路径包含了Go的编译器(cmd/gc或后续的cmd/go)、标准库的源码以及其他与Go运行时系统相关的组件。

      • GOPATH

GoROOT不同,GoPATH是一个用于存放Go项目依赖库、第三方包以及你的Go代码的目录。它是一个工作空间,让你可以管理多个Go项目而不会互相冲突。

    • 配置lanuch.json配置文件。

二、GO 文件结构

  • 基本结构

    • 包声明

    • 引入包

    • 变量

    • 函数

    • 语句表达式

    • 注释

    • // 包声明
      package main
      
      //导入fmt包
      import "fmt"
      
      // 函数声明
      func printInConsole(s string) {
          fmt.Println(s)
      }
      
      // 全局变量声明
      var str string = "Hello, world"
      
      // 主函数
      func main() {
          printInConsole(str) //调用函数
      }
  • 初始化顺序

    初始化底层包的顺序: 常量 → 变量 → init函数, 其中init函数有go的runtime调用。

Snipaste_2025-10-04_13-30-18

  

 三、基本数据类型

  • 基本类型

    • 数字

      • 整形

        • int8  uint8
        • int16  uint16
        • int32  uint32
        • int64  uint64
        • intuint,具体长度取决于 CPU 位数。
      • 浮点性

        • float32 
        • float64
          • var float1 float32 = 10
          • float2 := 10.0 (自动类型推导)自动设置为float64.
      • 复数

        • complex64   
        • complex128

var a complex64 = a + bi  a是实部, b是虚部,当a = 0是 a就是常见的实数, 当b= 0是, a就是纯虚数。

        • go 提供内置函数real和imag, 分别回去复数的实部和虚部

c1 = 1.10 + 0.1i

x := real(c1)

y := imag(c1)

      • byte类型

        • byte是uint8的别名, 可以吧byte和uint8视为同一种类型。
        • package main
          import "fmt"
          func main() {
              var s string = "Hello, world!"
              var bytes []byte = []byte(s)
          
              fmt.Println(bytes)
              fmt.Println(string(bytes))
              fmt.Println(string(bytes) == s)
          }
          结果:
          [72 101 108 108 111 44 32 119 111 114 108 100 33]
          Hello, world!
          true
           
      • rune类型

rune是uint32的别名, 可以吧rune和uint32视为同一种类型。

    • 字符串

string

只能用一对双引号("")或反引号(``)括起来定义,不能用单引号('')定义!

    • 布尔

bool

只有 true 和 false,默认为 false。

    • 零值

    数字类型是0

字符串类型是空

布尔类型是false

接口和引用类型为nil

  • 聚合类型

    • 数组

      • 声明

        • func main() {
              // 仅声明
              var a [5]int
              fmt.Println("a = ", a)
          
              // 声明以及初始化
              var b [5]int = [5]int{1, 2, 3, 4, 5}
              fmt.Println("b = ", b)
          
              // 类型推导声明方式
              var c = [5]string{"c1", "c2", "c3", "c4", "c5"}
              fmt.Println("c = ", c)
          
              d := [3]int{3, 2, 1}
              fmt.Println("d = ", d)
          
              // 使用 ... 代替数组长度
              autoLen := [...]string{"auto1", "auto2", "auto3"}
              fmt.Println("autoLen = ", autoLen)
          
              // 声明时初始化指定下标的元素值
              positionInit := [5]string{1: "position1", 3: "position3"}
              fmt.Println("positionInit = ", positionInit)
              
              // 初始化时,元素个数不能超过数组声明的长度
              //overLen := [2]int{1, 2, 3}
          }
      • 访问

        • func main() {
              a := [5]int{5, 4, 3, 2, 1}
          
              // 方式1,使用下标读取数据
              element := a[2]
              fmt.Println("element = ", element)
          
              // 方式2,使用range遍历
              for i, v := range a {
                  fmt.Println("index = ", i, "value = ", v)
              }
          
              for i := range a {
                  fmt.Println("only index, index = ", i)
              }
          
              // 读取数组长度
              fmt.Println("len(a) = ", len(a))
              // 使用下标,for循环遍历数组
              for i := 0; i < len(a); i++ {
                  fmt.Println("use len(), index = ", i, "value = ", a[i])
              }
          }
      • 多维数组

        • func main() {
              // 二维数组
              a := [3][2]int{
                  {0, 1},
                  {2, 3},
                  {4, 5},
              }
              fmt.Println("a = ", a)
          
              // 三维数组
              b := [3][2][2]int{
                  {{0, 1}, {2, 3}},
                  {{4, 5}, {6, 7}},
                  {{8, 9}, {10, 11}},
              }
              fmt.Println("b = ", b)
          
              // 也可以省略各个位置的初始化,在后续代码中赋值
              c := [3][3][3]int{}
              c[2][2][1] = 5
              c[1][2][1] = 4
              fmt.Println("c = ", c)
          }
        • 数组作为参数

    • 切片

      • 声明初始化

        • // 方式1,声明并初始化一个空的切片
          var s1 []int = []int{}
          
          // 方式2,类型推导,并初始化一个空的切片
          var s2 = []int{}
          
          // 方式3,与方式2等价
          s3 := []int{}
          
          // 方式4,与方式1、2、3 等价,可以在大括号中定义切片初始元素
          s4 := []int{1, 2, 3, 4}
          
          // 方式5,用make()函数创建切片,创建[]int类型的切片,指定切片初始长度为0
          s5 := make([]int, 0)
          
          // 方式6,用make()函数创建切片,创建[]int类型的切片,指定切片初始长度为2,指定容量参数4
          s6 := make([]int, 2, 4) 
          
          // 方式7,引用一个数组,初始化切片
          a := [5]int{6,5,4,3,2}
          // 从数组下标2开始,直到数组的最后一个元素
          s7 := arr[2:]
          // 从数组下标1开始,直到数组下标3的元素,创建一个新的切片
          s8 := arr[1:3]
          // 从0到下标2的元素,创建一个新的切片
          s9 := arr[:2]
      • 使用切片

        • 访问
          • 切片访问和数组一样
          • 切片还可以使用 len() 和 cap() 函数访问切片的长度和容量。当切片是 nil 时,len() 和 cap() 函数获取的到值都是 0。
        • 添加
          • ppend函数追加元素
            s3 = append(s3)
            s3 = append(s3, 1)
        • 复制
          • 可以使用内置函数 copy() 把某个切片中的所有元素复制到另一个切片,复制的长度是它们中最短的切片长度。
    • map集合

      • 声明
        • 方式 1,仅声明 mapvar <map name> map[<key type>]<value type>
          方式 2,使用内置函数 make() 初始化:
          
          <map name> := make(map[<key type>]<value type>)
          
          // 还可以使用map,提前指定容量
          <map name> := make(map[<key type>]<value type>, <capacity>)
          指定合适的初始容量,可以减少使用 map 存储键值对时触发扩容,减少扩容操作可以提高一些使用 map 的性能。
          
          方式 3,在初始化时,同时插入键值对:
          
          // 不会插入任何键值对
          <map name> := map[<key type>]<value type> {}
          
          // 插入键值对
          <map name> := map[<key type>]<value type> {
              <key1>: <value1>,
              <key2>: <value2>,
              ...
          }
      • 使用

        • 获取元素:
          
          <value> := <map name>[<key>]
          
          <value>,<exist flag> := <map name>[<key>]
          插入或修改键值对:
          
          <map name>[<key>] = <value>
          通过内置函数 len() 获取 map 中键值对数量:
          
          length := len(<map name>)
          遍历 map 集合:
          
          for <key name>, <value name> := range <map name> {
              <expression>
              ...
          }
          
          for <key name> := range <map name> {
              <expression>
              ...
          }
          使用内置函数 delete() 删除 map 集合中指定 key:
          
          delete(<map name>, <key>)
    • 结构体

      1. go中没有类的概念
      2. go中全局变量、全局常量、结构体、字段、方法只有公开类型和非公开类型。公开类型首字母大写, 非公开类型首字母小写。
      • 定义结构体

        type Address struct {
              name string 
              street string
              city string
              state string
              Pincode int
        }
      • 定义匿名字段

结构体中的字段不是一定要有字段名,也可以仅定义类型,这种只有类型没有字段名的字段被称为匿名字段

        • type Custom struct {
              int
              string
              Other string
          }

           

      • 匿名结构体

匿名结构体是没有定义名称的结构体

  • 方式 1,仅可在函数外声明,这种方式可以看成是声明了一个匿名的结构体,实例化后赋值给了的全局变量:
    • var <var name> = struct {
          <FiledName1> <type1> `<tag1>:"<any string>"`
          <FiledName2> <type2> `<tag2>:"<any string>"`
          ...
          <type3>
          <type4>
          ...
      } {
          <FiledName1>: <value1>,
          <FiledName2>: <value2>,
          ...
          <type3>: <value3>,
          <type4>: <value4>,
      }
    • 枚举

go中没有内置枚举类型,所以go中的枚举是使用const来定义枚举的。

枚举的本质就是一系列的常量。所以 Go 中使用 const 定义枚举,比如:

      • const (
            Male = "Male"
            Female = "Female"
        )
    • iota 关键字

      除了上面的别名类型来声明枚举类型以外,还可以使用 iota 关键字,来自动为常量赋值。
    • range关键字

range 关键字用于 for 循环迭代字符串(string)、数组(array)、切片(slice)、通道(channel)或映射集合(map)中的元素

      • 对字符串迭代

        • str1 := "abc123"
              for index := range str1 {
                  fmt.Printf("str1 -- index:%d, value:%d\n", index, str1[index])
              }
      • 对数组与切片迭代

        • // 方法1:只拿到数组的下标索引
              for index := range array {
                  fmt.Printf("array -- index=%d value=%d \n", index, array[index])
              }
              for index := range slice {
                  fmt.Printf("slice -- index=%d value=%d \n", index, slice[index])
              }
              fmt.Println()
          
              // 方法2:同时拿到数组的下标索引和对应的值
              for index, value := range array {
                  fmt.Printf("array -- index=%d index value=%d \n", index, array[index])
                  fmt.Printf("array -- index=%d range value=%d \n", index, value)
              }
              for index, value := range slice {
                  fmt.Printf("slice -- index=%d index value=%d \n", index, slice[index])
                  fmt.Printf("slice -- index=%d range value=%d \n", index, value)
              }
      • 对通道迭代

        • for i := range ch {
                  fmt.Println(i)
              }
      • 对映射集合迭代

        • package main
          
          import "fmt"
          
          func main() {
              hash := map[string]int{
                  "a": 1,
                  "f": 2,
                  "z": 3,
                  "c": 4,
              }
          
              for key := range hash {
                  fmt.Printf("key=%s, value=%d\n", key, hash[key])
              }
          
              for key, value := range hash {
                  fmt.Printf("key=%s, value=%d\n", key, value)
              }
          }
  • 引用类型

    • 指针

      • 声明和初始化

      • package main
        import "fmt"
        func main() {
        
            //定义一个正常变量
            var x int = 5748
        
            //指针声明
            var p *int
        
            //初始化指针
            p = &x
        
            //显示结果
            fmt.Println("存储在x中的值 = ", x)
            fmt.Println("x的内存地址 = ", &x)
            fmt.Println("存储在变量p中的值 = ", p)
        }输出:
        存储在x中的值 =  5748
        x的内存地址 =  0xc000066090
        存储在变量p中的值 =  0xc000066090
      • 指针解引用

      • package main
        
        import "fmt"
        
        func main() {
        
            //使用var关键字
            //我们没有定义
            //任何带变量的类型
            var y = 458
        
            //使用指针变量
            // var关键字,不指定
            //类型
            var p = &y
        
            fmt.Println("存储在y中的值 = ", y)
            fmt.Println("y的地址= ", &y)
            fmt.Println("存储在指针变量p中的值 = ", p)
        
            //这是取消引用指针
            //在指针之前使用*运算符
            //变量以访问存储的值
            //指向它所指向的变量
            fmt.Println("存储在y中的值(*p) = ", *p)
        
        }
        结果:
            存储在y中的值 =  458
            y的地址=  0xc0000120a8
            存储在指针变量p中的值 =  0xc0000120a8
            存储在y中的值(*p) =  458
      • 双指针

  • 类型转换

    • 注意
  • 不支持自动类型转换或隐式类型转换,对于类型转换,必须执行显式转换。
    • package main
      import "fmt"
      
      func main() {
      
          var totalsum int = 446
          var number int = 23
          var avg float32
      
          // 显式类型转换
          avg = float32(totalsum) / float32(number)
      
          // 显示结果
          fmt.Printf("平均值 = %f\n", avg)
      }
  • 不允许在表达式中混合使用数字类型(例如加,减,乘,除等),并且不允许在两个混合类型之间执行赋值类型。
    • var cainiaojc1 int64 = 875
      
      //它会在编译时抛出错误给我们
      //因为正在执行混合类型,例如把int64作为int类型
      var cainiaojc2 int = cainiaojc1
      
      var cainiaojc3 int = 100
      //它抛出编译时错误
      //这是无效操作
      //因为类型是混合的 int64 和 int 相加
      var addition = cainiaojc1 + cainiaojc3
    • 数字类型转换

      • 数字类型之间相互转换比较简单,并且位数较多的类型向位数较少的类型转换时,高位数据会被直接截去。
      • package main
        
        import "fmt"
        
        func main() {
            var i int32 = 17
            var b byte = 5
            var f float32
            
            // 数字类型可以直接强转
            f = float32(i) / float32(b)
            fmt.Printf("f 的值为: %f\n", f)
            
            // 当int32类型强转成byte时,高位被直接舍弃
            var i2 int32 = 256
            var b2 byte = byte(i2)
            fmt.Printf("b2 的值为: %d\n", b2)
        }
    • 字符串类型转换

string 类型、[]byte 类型与[]rune 类型之间可以类似数字类型那样相互转换,并且数据不会有任何丢失

      • package main
        
        import "fmt"
        
        func main() {
            str := "hello, 123, 你好"
            var bytes []byte = []byte(str)
            var runes []rune = []rune(str)
            fmt.Printf("bytes 的值为: %v \n", bytes)
            fmt.Printf("runes 的值为: %v \n", runes)
        
            str2 := string(bytes)
            str3 := string(runes)
            fmt.Printf("str2 的值为: %v \n", str2)
            fmt.Printf("str3 的值为: %v \n", str3)
        }

        数字与字符串相互转换的需求,这时需要使用到 go 提供的标准库 strconv

      • package main
        
        import (
            "fmt"
            "strconv"
        )
        
        func main() {
            str := "123"
            num, err := strconv.Atoi(str)
            if err != nil {
                panic(err)
            }
            fmt.Printf("字符串转换为int: %d \n", num)
            str1 := strconv.Itoa(num)
            fmt.Printf("int转换为字符串: %s \n", str1)
        
            ui64, err := strconv.ParseUint(str, 10, 32)
            fmt.Printf("字符串转换为uint64: %d \n", num)
        
            str2 := strconv.FormatUint(ui64, 2)
            fmt.Printf("uint64转换为字符串: %s \n", str2)
        }
        最常见的转换是字符串与 int 类型之间相互转换。也就是 Atoi 方法与 Itoa 方法。
        
        当需要把字符串转换成无符号数字时,目前只能转换成 uint64 类型,需要其他位的数字类型需要从 uint64 类型转到所需的数字类型。
        
        同时可以看到当使用 ParseUint 方法把字符串转换成数字时,或者使用 FormatUint 方法把数字转换成字符串时,都需要提供第二个参数 base,这个参数表示的是数字的进制,即标识字符串输出或输入的数字进制。
    • 接口类型转换

      • package main
        
        import "fmt"
        
        func main() {
            var i interface{} = 3
            a, ok := i.(int)
            if ok {
                fmt.Printf("'%d' is a int \n", a)
            } else {
                fmt.Println("conversion failed")
            }
        }
    • 结构体类型转换

      • package main
        
        import "fmt"
        
        type SameFieldA struct {
            name  string
            value int
        }
        
        type SameFieldB struct {
            name  string
            value int
        }
        
        func (s *SameFieldB) getValue() int {
            return s.value
        }
        
        func main() {
            a := SameFieldA{
                name:  "a",
                value: 1,
            }
        
            b := SameFieldB(a)
            fmt.Printf("conver SameFieldA to SameFieldB, value is : %d \n", b.getValue())
            
            // 只能结构体类型实例之间相互转换,指针不可以相互转换
            // var c interface{} = &a
            // _, ok := c.(*SameFieldB)
            // fmt.Printf("c is *SameFieldB: %v \n", ok)
        }

         

四、变量、常量和运算符

  • 变量

    • 使用var关键字声明

    • package main
      import "fmt"
      func main() {
      
          //变量声明和初始化
          //显式类型
          var myvariable1 = 20
          var myvariable2 = "cainiaojc"
          var myvariable3 = 34.80
      
          // Display the value and the
          // type of the variables
          fmt.Printf("myvariable1的值是 : %d\n", myvariable1)
          fmt.Printf("myvariable1的类型是 : %T\n", myvariable1)
          fmt.Printf("myvariable2的值是 : %s\n", myvariable2)
          fmt.Printf("myvariable2的类型是 : %T\n", myvariable2)
          fmt.Printf("myvariable3的值是 : %f\n", myvariable3)
          fmt.Printf("myvariable3的类型是 : %T\n", myvariable3)
      }
      结果

      myvariable1的值是 : 20
      myvariable1的类型是 : int
      myvariable2的值是 : cainiaojc
      myvariable2的类型是 : string
      myvariable3的值是 : 34.800000
      myvariable3的类型是 : float64

      • 使用var关键字的要点
        • 在使用var关键字声明变量期间,可以省略 type 或= 表达式,但不能同时省略。如果这样做,编译器将抛出一个错误
        • Go语言中没有这样的未初始化变量的概念。
    • 使用短变量声明

      • variable_name:= expressio
      • package main
        import "fmt"
        func main() {
        
            // 使用短变量声明
            myvariable1 := 39
            myvariable2 := "(cainiaojc.com)"
            myvariable3 := 34.67
        
            // 打印变量值和类型
            fmt.Printf("myvariable1的值是 : %d\n", myvariable1)
            fmt.Printf("myvariable1的类型是 : %T\n", myvariable1)
            fmt.Printf("\nmyvariable2的值是 : %s\n", myvariable2)
            fmt.Printf("myvariable2的类型是 : %T\n", myvariable2)
            fmt.Printf("\nmyvariable3的值是 : %f\n", myvariable3)
            fmt.Printf("myvariable3的类型是 : %T\n", myvariable3)
        }
        结果:
        myvariable1的值是 : 39
        myvariable1的类型是 : int
        myvariable2的值是 : (cainiaojc.com)
        myvariable2的类型是 : string
        myvariable3的值是 : 34.670000
        myvariable3的类型是 : float64 
  • 常量

使用const 关键字作为前缀来声明具有特定类型的常量。不能使用:=语法声明。

    • 分类

      • 数值常量(整数常量,浮点常量,复数常量)

      • 字符串字面量

      • 布尔常量

  • 运算符

    • 算术运算符
    • 关系运算符
    • 逻辑运算符
    • 按位运算符
    • 赋值运算符
    • 杂项运算符

 

 

 

 

 

 

 

 

 

posted @ 2025-10-04 14:02  直至成伤  阅读(14)  评论(0)    收藏  举报