Go 语法基础(三)| 青训营笔记

97 阅读4分钟

类型转换

Go 语言不存在隐式类型转换,因此所有的类型转换都必须显式的声明

type_name(expression)

数值类型转换

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

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

var a int = 10
var b float64 = float64(a)

字符串类型转换

var str string = "10"
var num int
num, _ = strconv.Atoi(str)

接口类型转换

类型断言

类型断言用于将接口类型转换为指定类型,其语法如下

value.(T)

其中 value 是接口类型的变量,T 是要转换成的类型

package main
​
import "fmt"func main() {
    var i interface{} = "Hello, World"
    str, ok := i.(string)
    if ok {
        fmt.Printf("'%s' is a string\n", str)
    } else {
        fmt.Println("conversion failed")
    }
}

类型转换

在类型转换中,我们必须保证要转换的值和目标接口类型之间是兼容的,否则编译器会报错

package main
​
import "fmt"type Writer interface {
    Write([]byte) (int, error)
}
​
type StringWriter struct {
    str string
}
​
func (sw *StringWriter) Write(data []byte) (int, error) {
    sw.str += string(data)
    return len(data), nil
}
​
func main() {
    var w Writer = &StringWriter{}
    sw := w.(*StringWriter)
    sw.str = "Hello, World"
    fmt.Println(sw.str)
}

变量

标识符

  • 由数字(0~9)和字母(A~Z 和 a~z)、下划线(_)组成,但不能以数字开头
  • 不可以是关键字或保留字
  • 严格区分大小写
  • 不能包含空格

声明

Go 语言主要有四种类型的声明语句:varconsttypefunc,分别对应变量、常量、类型和函数实体对象的声明

var 声明语句可以创建一个特定类型的变量,然后给变量附加一个名字,并且设置变量的初始值

var a int

短变量声明

在函数内部,有一种称为简短变量声明语句的形式可用于声明和初始化局部变量。它以“名字 := 表达式”形式声明变量,变量的类型根据表达式来自动推导

i := 100 // an int

nil 是 Go 语言中预先声明的标识符(非关键字保留字),其主要用来表示引用类型的零值(指针,接口,函数,映射,切片和通道),表示它们未初始化的值

// [src/builtin/builtin.go](https://golang.org/src/builtin/builtin.go#L98)
//
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

nil 是 Go 语言中唯一没有默认类型的非类型化的值,它不是一个未定义的状态,所以不能用于短变量声明

a := nil // 编译出错

初始化

在声明变量时,自动对变量对应的内存区域进行初始化操作。每个变量会初始化其类型的默认值:

  • 整型和浮点型变量的默认值为 0 和 0.0
  • 字符串变量的默认值为空字符串
  • 布尔型变量默认为 bool
  • 切片、函数、指针变量的默认为 nil

结构体初始化

stu := &Student{
    "张三",
    24
}
stu := &Student{
    Name: "张三",
    Age: 24
}
stu := new(Student)
stu.Name = "张三"
stu.Age = 24

赋值

使用赋值语句可以更新一个变量的值,最简单的赋值语句是将要被赋值的变量放在=的左边,新值的表达式放在=的右边

x = 1                       // 命名变量的赋值
*p = true                   // 通过指针间接赋值
person.name = "bob"         // 结构体字段赋值
count[x] = count[x] * scale // 数组、slice或map的元素赋值

数值变量也可以支持 ++ 递增和 -- 递减语句,但不支持赋值

a = 1
a++

元组赋值

i, j, k = 2, 3, 5

作用域

一个声明语句将程序中的实体和一个名字关联,比如一个函数或一个变量。声明语句的作用域是指源代码中可以有效使用这个名字的范围

句法块是由花括弧所包含的一系列语句,就像函数体或循环体花括弧包裹的内容一样。句法块内部声明的名字是无法被外部块访问的。这个块决定了内部声明的名字的作用域范围

逃逸分析

  • 在某个函数中 new 或字面量创建出的变量,将其指针作为函数返回值,则该变量一定发生逃逸
  • 被已经逃逸的变量引用的指针,一定发生逃逸
  • 被指针类型的 slice、map 和 chan 引用的指针,一定发生逃逸