声明
本系列文章并不会停留在Go语言的语法层面,更关注语言特性、学习和使用中出现的问题以及引起的一些思考。
要点
本文只关注Go语言的基本类型:如整型、浮点型、常量相关的内容。字符串、数组和切片等高级类型会在下一篇文章中讲述。
包
初始化顺序:当前包级别变量 -> 导入外部包的init() -> 当前包内的init() -> main()。通常可将一个包导入但是不使用的方式,初始化某些配置数据。
下面这段代码会运行config包和model包下的init()方法:
import (
"cmdb-bg/cmd"
_ "cmdb-bg/config"
_ "cmdb-bg/model"
)
零值
我们都知道,当我们仅仅声明一个变量、但未对其进行初始化的时候,Go会给每种变量类型赋一个零值:
- 整型:0
- 浮点型:0
- bool型:false
func main() {
var a int
var b float64
var c bool
fmt.Println(a, b, c) // 0 0 false
}
赋值与类型推断
如果你之前已经使用了":="对某个变量进行了声明与初始化,如果你想再次为这个变量进行重新赋值,切记不要加":"
func main() {
a := 1
a := 2
fmt.Println(a) // 报错:no new variables on left side of :=
a = 2 // ok
}
func main() {
var a int = 1
for a >= 1 {
a := 2 // 无限循环
a = 2 // 正常执行
a = a-2
fmt.Println(a)
}
}
Go中可以用如下方式高效交换两个变量的值:
func main() {
a := 0
b := 1
a, b = b, a // 交换,不需要使用临时变量
fmt.Println(a, b) // 1, 0
}
- Go的new()返回的是一个地址,而不是值本身:
func main() {
a := new(int)
fmt.Println(a) // 0xc000016050
}
if赋值加判断复合语句的作用域:f的作用域会被限制在if大括号所包裹的代码块内。在if的外部并不能使用变量f:
func f1() error {
if f, err := os.Open("abc"); err != nil {
return err
}
fmt.Println(f) // 编译不通过: undefined: f
}
// 解决:
func f1() error {
f, err := os.Open("abc")
if err != nil {
return err
}
f.Close() // ok
}
运算与类型转换
int和int32是不同类型,若要把int当成int32来使用,必须进行强制类型转换。其他类型同理。
类型断言的使用(暂作了解):
func main() {
// a必须是空接口类型, 任何类型都是interface的实现类,当声明为interface{}时,可以赋值给他任意类型
var a interface{}
a = 2;
// 类型断言会返回两个值
v, ok := a.(int)
// 如果变量a是断言的类型,ok为true,v为被断言变量的值。
// 否则ok为false,v为断言类型的零值
fmt.Println(v, ok) // 2 true
}
如果进行算术运算之后发生了溢出,那么Go会直接丢掉溢出的高位部分。
所有基本类型的值都是可以比较的(整型、浮点型),其他高级类型的比较,一部分需要遵循一定规则,而一部分高级类型是禁止比较的。
不同数据类型不能直接做运算。不像其他语言,Go语言没有隐式类型转换。要想强制对不同类型做运算,必须进行显式的强制类型转换。转换成同一种类型之后,才能做运算:
func main() {
var a int8 = 100
var b int16 = 100
fmt.Println(a + b) // invalid operation: a + b (mismatched types int8 and int16)
fmt.Println(int16(a) + b) // ok
}
在进行强制类型转换时需要注意:当整数值的类型的有效范围由宽变窄时,会截掉一定数量的高位二进制数。与这个类似的还有把一个浮点数类型的值转换为整数类型值时,浮点数类型的小数部分会被全部截断:
func main() {
var a int16 = 428 //00000001 10101100
fmt.Println(int8(a)) // -84
// 截断高8位为:10101100。Go中用二进制补码表示数值。转成原码为为 11010100 即十进制-84
}
浮点数的精度有限,尽量不要做浮点数运算结果的比较:
func main() {
var f float32 = 16777216 // 1 << 24
fmt.Println(f == f+1) // false
var a float32 = 1.23
var b float32 = 1.25
fmt.Println(a-b) // -0.01999998
}
iota常量让用二进制位做标记更简单了。在第一个声明的常量所在的行,iota将会被置为0,然后在每一个有常量声明的行加一:
const (
FlagUp Flags = 1 << iota // 第一种标记
FlagBroadcast // 第二种标记
FlagLoopback // 第三种标记
FlagPointToPoint // 第四种标记
FlagMulticast // 第五种标记
)
下期预告
【Go语言踩坑系列(二)】字符串
有疑问加站长微信联系(非本文作者)