GO语言基本语法

GO语言基本语法

GO语言变量声明

  1. var name type

    var a int
    
  2. 批量声明

    var(
        a int
        b string
        c []float32
        d func()bool
        e struct {
            x int
        }
    )
    
  3. 简短格式

    名字:=表达式

    -定义变量,同时显式初始化

    -不能提供数据类型

    -只能用在函数内部

    GO语言的基本数据类型:

    • bool
    • string
    • int,int 8,int 16,int 32,int 64
    • uint,uint 8,uint 16,uint 32,uint 64,uintptr
    • byte//uint8的别名
    • rune//int32的别名,代表一个unicode码
    • complex64,comlpex128

    GO语言变量的初始化

    var name type=表达式
    var a int=100
    
    var name=表达式
    vr a =100
    
    name:=表达式
    a:=100
    

    匿名变量

    _,_=表达式,表达式
    

    GO语言变量的作用域

    全局 局部 形参

    string

    1. 使用“ ”定义字符串

      var a="hello word"
      
      
      1. 拼接字符串
      s1:=s2+s3
      s1+=s2
      
      Go 语言中也有类似于 StringBuilder 的机制来进行高效的字符串连接
      
      hammer := "吃我一锤"
      
      sickle := "死吧"
      
      // 声明字节缓冲
      var stringBuilder bytes.Buffer
      
      // 把字符串写入缓冲
      stringBuilder.WriteString(hammer)
      stringBuilder.WriteString(sickle)
      
      // 将缓冲以字符串形式输出
      fmt.Println(stringBuilder.String())
      
      bytes.Buffer 是可以缓冲并可以往里面写入各种字节数组的。字符串也是一种字节数组,使用 WriteString() 方法进行写入。
      
      将需要连接的字符串,通过调用 WriteString() 方法,写入 stringBuilder 中,然后再通过 stringBuilder.String() 方法将缓冲转换为字符串。
      
      1. 定义多行字符串
      const str=`第一行
      第二行
      第三行
      \r\n
      `
      
    2. 字符串长度

      GO语言可以使用内建函数len(),可以获取切片、字符串、通道(channel)等的长度
      
      tip1 := "genji is a ninja"
      fmt.Println(len(tip1))
      
      tip2 := "忍者"
      fmt.Println(len(tip2))
      程序输出
      16
      6
      
      
      len()函数的返回值时int,表示字符串的ASCLL字符的个数
      
      Go 语言中 UTF-8 包提供的 RuneCountInString() 函数,统计 Uncode 字符数量
      
      fmt.Println(utf8.RuneCountInString("忍者"))
      fmt.Println(utf8.RuneCountInString("龙忍出鞘,fight!"))
      
      程序输出如下:
      2
      11
      
      • ASCII 字符串长度使用 len() 函数。
      • Unicode 字符串长度使用 utf8.RuneCountInString() 函数。
    3. 遍历字符串

      遍历每一个ASCII字符
      
      theme := "狙击 start"
      
      for i := 0; i < len(theme); i++ {
          fmt.Printf("ascii: %c  %d\n", theme[i], theme[i])
      }
      程序输出:
      ascii: ?  231
      ascii:     139
      ascii:     153
      ascii: ?  229
      ascii:     135
      ascii: ?  187
      ascii:    32
      ascii: s  115
      ascii: t  116
      ascii: a  97
      ascii: r  114
      ascii: t  116
      
      按Unicode字符遍历字符串
      
      theme := "狙击 start"
      
      for _, s := range theme {
          fmt.Printf("Unicode: %c  %d\n", s, s)
      }
      程序输出:
      Unicode: 狙  29401
      Unicode: 击  20987
      Unicode:    32
      Unicode: s  115
      Unicode: t  116
      Unicode: a  97
      Unicode: r  114
      Unicode: t  116
      
      • ASCII 字符串遍历直接使用下标。
      • Unicode 字符串遍历用 for range。
    4. 字符串的截取

      下面例子中使用 strings.Index() 函数在字符串中搜索另外一个子串,代码如下
      
      tracer := "死神来了, 死神bye bye"
      comma := strings.Index(tracer, ", ")
      
      pos := strings.Index(tracer[comma:], "死神")
      
      fmt.Println(comma, pos, tracer[comma+pos:])
      
      程序输出:
      12 3 死神bye bye
      
      • strings.Index:正向搜索子字符串。
      • strings.LastIndex:反向搜索子字符串。
      • 搜索的起始位置可以通过切片偏移制作
    5. 修改字符串

      ​ Go 语言的字符串无法直接修改每一个字符元素,只能通过重新构造新的字符串并赋值给原来的字符串变量实现

      angel := "Heros never die"
      
      angleBytes := []byte(angel)
      
      for i := 5; i <= 10; i++ {
          angleBytes[i] = \' \'
      }
      
      fmt.Println(string(angleBytes))
      
      程序输出如下:
      Heros       die
      

      ​ 感觉我们通过代码达成了修改字符串的过程,但真实的情况是:Go 语言中的字符串和其他高级语言(JavaC#)一样,默认是不可变的(immutable)。

      ​ 字符串不可变有很多好处,如天生线程安全,大家使用的都是只读对象,无须加锁;再者,方便内存共享,而不必使用写时复制(Copy On Write)等技术;字符串 hash 值也只需要制作一份

      • Go 语言的字符串是不可变的。
      • 修改字符串时,可以将字符串转换为 []byte 进行修改。
      • []byte 和 string 可以通过强制类型转换互转。
    6. fmt.Sprintf

      fmt.Sprintf(格式化样式, 参数列表…)
      
      fmt.Println(title)
      
      pi := 3.14159
      // 按数值本身的格式输出
      variant := fmt.Sprintf("%v %v %v", "月球基地", pi, true)
      
      "月球基地" 3.14159 true
      
      动 词功 能
      %v按值的本来值输出
      %+v在 %v 基础上,对结构体字段名和值进行展开
      %#v输出 Go 语言语法格式的值
      %T输出 Go 语言语法格式的类型和值
      %%输出 % 本体
      %b整型以二进制方式显示
      %o整型以八进制方式显示
      %d整型以十进制方式显示
      %x整型以十六进制方式显示
      %X整型以十六进制、字母大写方式显示
      %UUnicode 字符
      %f浮点数
      %p指针,十六进制方式显示
    7. Base64 编码

      ​ Base64 编码是常见的对 8 比特字节码的编码方式之一。Base64 可以使用 64 个可打印字符来表示二进制数据,电子邮件就是使用这种编码。

      ​ Go 语言的标准库自带了 Base64 编码算法,通过几行代码就可以对数据进行编码,示例代码如下。

      package main
      
      import (
          "encoding/base64"
          "fmt"
      )
      
      func main() {
      
          // 需要处理的字符串
          message := "Away from keyboard. https://golang.org/"
      
          // 编码消息
          encodedMessage := base64.StdEncoding.EncodeToString([]byte (message))
      
          // 输出编码完成的消息
          fmt.Println(encodedMessage)
      
          // 解码消息
          data, err := base64.StdEncoding.DecodeString(encodedMessage)
      
          // 出错处理
          if err != nil {
              fmt.Println(err)
          } else {
              // 打印解码完成的数据
              fmt.Println(string(data))
          }
      }
      

GO语言字符串类型

Go语言的字符有以下两种:

  • 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。

  • 另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型等价于 int32 类型。

    在 ASCII 码表中,A 的值是 65,使用 16 进制表示则为 41,所以下面的写法是等效的:

    var ch byte = 65 或 var ch byte = \'\x41\'   //(\x 总是紧跟着长度为 2 的 16 进制数)
    

    另外一种可能的写法是\后面紧跟着长度为 3 的八进制数,例如 \377。

​ Go语言同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,并在内存中使用 int 来表示。在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数。

​ 格式化说明符%c用于表示字符,当和字符配合使用时,%v%d会输出用于表示该字符的整数,%U输出格式为 U+hhhh 的字符串。

Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表字符):

  • 判断是否为字母:unicode.IsLetter(ch)
  • 判断是否为数字:unicode.IsDigit(ch)
  • 判断是否为空白符号:unicode.IsSpace(ch)

GO语言数据类型转化

valueOfTypeB = typeB(valueOfTypeA)

​ 类型转换只能在定义正确的情况下转换成功,例如从一个取值范围较小的类型转换到一个取值范围较大的类型(将 int16 转换为 int32)。当从一个取值范围较大的类型转换到取值范围较小的类型时(将 int32 转换为 int16 或将 float32 转换为 int),会发生精度丢失(截断)的情况。

​ 只有相同底层类型的变量之间可以进行相互转换(如将 int16 类型转换成 int32 类型),不同底层类型的变量相互转换时会引发编译错误(如将 bool 类型转换为 int 类型):

GO语言指针

指针(pointer)在Go语言中可以被拆分为两个核心概念:

  • 类型指针,允许对这个指针类型的数据进行修改,传递数据可以直接使用指针,而无须拷贝数据,类型指针不能进行偏移和运算。
  • 切片,由指向起始元素的原始指针、元素数量和容量组成。

GO语言变量逃逸

使用 go run 运行程序时,-gcflags 参数是编译参数。其中 -m 表示进行内存分配分析,-l 表示避免程序内联,也就是避免进行程序优化

编译器觉得变量应该分配在堆和栈上的原则是:

  • 变量是否被取地址;
  • 变量是否发生逃逸。