Go语言基础必备知识点(一) 变量篇

1. 变量声明

与其他语言不同,当一个变量被声明之后,系统自动初始化,赋予它该类型的零值:
int 为 0float 为 0.0bool 为 falsestring 为空字符串指针为 nil 注意:所有的内存在 Go 中都是经过初始化的

  1. 标准声明
var name type

变量声明以关键字 var 开头,变量类型 type 后置,行尾无须分号

  • 对比 C 语言这样的声明方式:int* a, b ,只有a是指针,b不是,这样可能会使人迷惑 -.-
    如果想要两个变量都为指针,需要这样两个*定义:int *a,*b
  • 而在 Go 语言这样 type 后置的声明方式:var a,b *int,就可以轻松的将a,b都声明为指针!
  1. 不指明变量类型声明
//设置年龄并赋值为24 编译时自动推导为int类型
var age = 24

像上面这种并没有指明类型声明变量的方式,在编译时会自动推导类型

  1. 批量声明
var (
    a int
    b string
    c []float32   //默认精度为6
)

若觉得每行都用 var 声明变量比较烦琐,可以用 Go 语言提供的批量声明的方式,用括号()括起来

  1. 短变量声明 (函数内最常用)
    不指明变量类型的更简短写法,省略 var 关键字,写起来更加便捷
//设置年龄并赋值为24 编译时自动推导为int类型
age := 24

注意:

  • 短变量声明只可存在于函数内部,不可以在全局变量中
  • 短变量声明被广泛用于大部分的局部变量的声明和初始化,var 形式的声明语句往往用于需要显式指定变量类型的地方
  • *在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名是重复声明的,编译器也不会报错
    比如下面代码的短变量声明也是可以的:
package main

import (
    "fmt"
    "net"
)

func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:8080")
    conn1, err := net.Dial("tcp", "127.0.0.1:8080")
}
  • net.Dial 提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象 (conn) ,一个是错误对象 (err)

*2. 匿名变量

  1. 使用多重赋值时,如果不需要在左值中接受变量,可以使用匿名变量
    比如上面的例子:
package main

import (
    "fmt"
    "net"
)

func main() {

    //conn, err := net.Dial("tcp", "127.0.0.1:8080")
    //如果只想接收conn,不想接收err的值,那么可以使用_表示,这就是匿名变量
    conn, _ := net.Dial("tcp", "127.0.0.1:8080")
    fmt.Println(conn)
}
  1. 注意:_本身就是一个特殊的标识符,被称为空白标识符
    它可以像其他标识符那样用于变量的声明或赋值 (任何类型都可以赋值给它) ,但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算
    继续上面的例子:
package main

import (
    "fmt"
    "net"
)

func main() {
    conn, _ := net.Dial("tcp", "127.0.0.1:8080")
    //匿名变量可以重复声明
    conn1, _ := net.Dial("tcp", "127.0.0.1:8080")
    // 匿名变量不可以直接开头
    _ :=1    //error
}

3. 变量作用域

了解变量的作用域对是比较重要的,因为Go语言 (静态语言) 会在编译时检查每个变量是否使用过,一旦出现未使用的变量,就会报编译错误

  1. 局部变量
    在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量都属于局部变量
    局部变量不是一直存在的,它只在定义它的函数被调用后存在,函数调用结束后这个局部变量就会被销毁。
  2. 全局变量
    函数外定义的变量称为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用 import 关键字引入全局变量所在的源文件之后才能使用这个全局变量
    Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑。
  3. *形式参数
    在定义函数时函数名后面括号中的变量叫做形式参数(简称形参)
    形式参数只在函数调用时才会生效,函数调用结束后就会被销毁,在函数未被调用时,函数的形参并不占用实际的存储单元,也没有实际值

4. 变量基本类型

  1. 整型
  • 有符号整型:int(随系统,一般是占4个字节)、int8(占1个字节)、int16(占2个字节)、int32(占4个字节)、int64(占8个字节)
  • 无符号整型:uint、uint8、uint16、uint32、uint64、uintptr
    (uintptr 没有指定具体的 bit 大小但是足以容纳指针)
    (uintptr 类型只有在底层编程时才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方)
  1. 浮点型
  • float32、float64
    通常应该优先使用 float64 类型,因为 float32 的累计计算误差很容易扩散,并且 float32 能精确表示的正整数并不是很大
var f float32 = 1 << 24;
fmt.Println(f == f+1) // true
  • 浮点数在声明的时候可以只写整数部分或者小数部分
var e = .71828 // 0.71828
var f = 1.     // 1
fmt.Printf("%.5f,%.1f",e,f)
  • 很小或很大的数最好用科学计数法书写,通过 e 或 E 来指定指数部分
var avogadro = 6.02214129e23  // 阿伏伽德罗常数
var planck   = 6.62606957e-34 // 普朗克常数
fmt.Printf("%f,%.35f",avogadro,planck)
  1. 布尔型
    ==><<=>=&&(AND)||(OR) 等都会产生bool值
  • Go语言对于值之间的比较有非常严格的限制,只有两个相同类型的值才可以进行比较,如果值的类型是接口 (interface) ,那么它们也必须都实现了相同的接口
  • 如果其中一个值是常量,那么另外一个值可以不是常量,但是类型必须和该常量类型相同
  • 如果以上条件都不满足,则必须将其中一个值的类型转换为和另外一个值的类型相同之后才可以进行比较
  • &&|| 是具有短路行为的 (&&优先级高于||)
    布尔型数据只有true和false,且不能参与任何计算以及类型转换
  1. 字符型
  • byte 类型,或者叫 uint8,代表了 ASCII 码的一个字符 (占一个字节),一般用于强调数值是一个原始的数据而不是一个小的整数
  • rune 类型,或者叫 int32,代表一个 UTF-8 字符 (Unicode 码) ,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型
    *Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表字符):
unicode.IsLetter(ch)  //判断是否为字母:
unicode.IsDigit(ch)   //判断是否为数字
unicode.IsSpace(ch)   //判断是否为空白符号
  1. 字符串型
    字符串string是一个不可改变的字节序列,可以包含任意的数据,但通常是用来包含可读的文本。字符串是 UTF-8 字符的一个序列
    字符串是字节的定长数组,byte 和 rune 都是字符类型,若多个字符放在一起,就组成了字符串
    Go语言从底层就支持UTF-8编码

UTF-8 是一种被广泛使用的编码格式,是文本文件的标准编码
由于该编码对占用字节长度的不定性,在Go语言中字符串也可能根据需要占用 1 至 4 个字节,这与其它编程语言不同
Go语言这样做不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码

  1. 字符串是一种值类型,且值不可变,即创建某个文本后将无法再次修改这个文本的内容
    如果使用``反引号,会被原样进行赋值和输出
fmt.Println("\t 我是\t") // 我是
fmt.Println(`\t 我是\t`) // \t 我是\t
fmt.Println(`\t 我
是\t`)                   //\t 我
                         //    是\t

使用反引号``可以进行字符串换行,一般用在需要将内容进行原样输出的时候使用

  1. *复数(complex)型
    Go语言提供了两种精度的复数类型:complex64和complex128, 其中,complex64 的实数和虚数部分都是 float32 类型,complex128 的实数和虚数部分都是 float64 类型
    语法:complex(real,imag) 内置的 complex 函数用于构建复数,内建的 real 和 imag 函数分别返回复数的实部和虚部:
package main

import "fmt"

func main() {
    var a complex64 = complex(1, 2)
    fmt.Print("a = ", a)       //a = 1 + 2i
    fmt.Println(real(a))       // 1
    fmt.Println(imag(a))       // 2
}

复数型个人感觉实际用处不太大,暂时了解即可