第3章 基础数据类型
Go语言将数据类型分为了四类:基础类型、符合类型、引用类型和接口类型。基础类型:数字、字符串和布尔型;复合数据类型:数组和结构体;引用类型:指针、切片、字典、函数、通道,虽然数据种类很多,但他们都是对程序中一个变量或状态的间接引用,这意味着对任一引用类型数据的修改都会影响所有该引用的拷贝
3.1 整型
Go语言的数值类型包括几种不同大小的整数、浮点数和复数
Go语言同时提供了有符号和无符号类型的整数运算,分别是int8/16/32/64和uint8/16/32/64(有符号和无符号)
Unicode字符rune类型是int32等价的类型,通常用于表示一个Unicode码点,它们可以互换使用。同样,byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始数据而不是一个小的整数
无符号整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程时才需要,特别是Go语言和C语言函数库或操作系统接口相互交互的地方
不管它们具体大小,int、uint和uintptr 是不同类型的兄弟类型,int和int32也是不同的类型,及时int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然
有符号整数采用2的补码形式表示,也就是最高bit未用来表示符号位,一个n-bit的有符号数值域是从-2的n-1次方到2的n-1次方-1,而无符号整数的所有bit位都用于表示非负数,值是0到2的n-1次方
算术、逻辑、比较运算符
* / % <<(左移) >>(右移) &(位运算 AND) &^(AND NOT) |
---|
+ - |(OR) ^(XOR) |
== != < <= > >== |
&& |
|| |
左移等价于*2的n次方,右移等价于除以2的n次方
类型转换
func main() {
var apples int32 = 1
var oranges int64 = 2
//var compote int = apples + oranges//compile error
var compote int = int(apples) + int(oranges)
fmt.Println(compote)
}
f := 3.14
i :=int(f)
fmt.Println(i)//3
fmt 格式化打印
c% 打印参数
%d 答应数值
%q 参数打印带单引号的字符
3.2 浮点数
Go语言提供了两种精度的浮点数,float32和float64
一个float32类型的浮点数可以提供大约6个十进制数的精度,一个float64类型的浮点数可以提供大约15个十进制数的精度,通常应该优先使用float64
格式化打印浮点数用 %g
const (
width, height = 600, 320
cells = 100
xyrange = 30.0
xyscale = width / 2 / xyrange
zscale = height * 0.4
angle = math.Pi / 6
)
var sin30, cos30 = math.Sin(angle), math.Cos(angle)
func main() {
fmt.Printf("svg xmlns = 'http://www.w3.org/2000/svg'"+
"style = 'stroke:grey; fill:white;stroke-width:0.7'"+
"width = '%d' height = '%d'>", width, height)
for i := 0; i < cells; i++ {
for j := 0; j < cells; j++ {
ax, ay := cornor(i+1, j)
bx, by := cornor(i, j)
cx, cy := cornor(i, j+1)
dx, dy := cornor(i+1, j+1)
fmt.Printf("<polygon points = '%g,%g %g,%g %g,%g %g,%g'/>\n",
ax, ay, bx, by, cx, cy, dx, dy)
}
}
fmt.Printf("</svg>")
}
func cornor(i, j int) (float64, float64) {
x := xyrange * (float64(i)/cells - 0.5)
y := xyrange * (float64(j)/cells - 0.5)
z := f(x, y)
sx := width/2 + (x-y)*cos30*xyscale
sy := height/2 + (x+y)*sin30*xyscale - z*zscale
return sy, sx
}
func f(x, y float64) float64 {
r := math.Hypot(x, y)
return math.Sin(r)
}
3.3 复数
Go语言提供了两种精度的复数类型:complex64和complex128;分别对应float32和float64两 种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实 部和虚部:
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y) // "(-5+10i)"
fmt.Println(real(x*y)) // "-5"
fmt.Println(imag(x*y))
x := 1 + 2i
y := 3 + 4i
3.4 布尔型
一个布尔类型值有两种:true和false
能产生布尔类型值的情况:if、for语句的条件部分,比较操作
布尔值可以和&&(and)和||(or)操作结合,并且有短路行为,即如果等号左边的值已经可以确定整个布尔表达式的值,那么运算符右边的值将不再被求值,因此下面的总是安全的:
s != "" && s[0] == 'x'
因为 && 的优先级比 || 高(助记: && 对应逻辑乘法, || 对应逻辑加法,乘法比加法优先 级要高),下面形式的布尔表达式是不需要加小括弧的:
if 'a' <= c && c <= 'z' ||
'A' <= c && c <= 'Z' ||
'0' <= c && c <= '9' {
// ...ASCII letter or digit...
}
布尔值并不会隐式转换为数字值0或1,反之亦然。必须使用一个显式的if语句辅助转换:
i := 0
if b {
i = 1
}
数字到布尔类型的转换
func itob(i int) bool { return i != 0 }
3.5 字符串
一个字符串是一个不可改变的字节序列
内置函数len()可以返回字符串中字节数目,用索引s[i]可以返回第i个字节的字节值,i必须满足0<= i <= len(s)
s := "hello, world"
fmt.Println(len(s))//12
fmt.Println(s[0],s[7])//104 119
使用字符串操作s[i:j]中的i和j,包左不包右
+操作可以将两个字符串链接构造成一个字符串
s := "hello, world"
fmt.Println("goodbye" + s[5:])//goodbye, world
字符串可以用==和<进行比较;比较是通过逐个字节比较完成的,因此比较的结果是字符串自然编码的顺序
字符串的值是不可变的:一个字符串包含的字节序列永远不会被改变,但是可以追加(原来的字节内容不可变)
s0 := "left foot"
t:=s0
s0 += ",right foot"
fmt.Println(s0,t)//left foot,right foot left foot
不变性意味着如果两个字符串共享的相同的底层数据的话也数安全的,这使得复制任何长度的字符串代价是低廉的,同样一个字符串可以和其切片共享相同的内存并且是安全的
3.5.1 字符串面值
只要将字节序列包含在“”中即可
"hello, 世界"
Go语言源文件总是用UTF8编码,并且Go语言的文本字符串也可以以UTF8编码的方式处理,因此我们可以将Unicode码点也写到字符串面值中
一个原生的字符串面值形式是...
,使用反引号代替双引号
原生字符串面值用于编写正则表达式会很方便,因为正则表达式往往会包含很多反斜杠。原生字符串面值同时被广泛应用于HTML模版、JSON面值、命令行提示信息以及那些需要扩展到多行的场景
const GoUsage = `Go is a tool for managing Go source code
Usage:
go command [arguments]
...`
3.5.2 Unicode
最早的ASCII字符集包含的符号系统有限,后来出现了Unicode,它收集了这个世界上所有的符号系统,包括重音符号和其他变音符号、制表符和回车符,还有很多神秘的符号,每个符号都分配了唯一的Unicode码点,Unicode码点对应Go语言中rune对应的类型
3.5.3 UTF-8
UTF-8是一个将Unicode码点编码为字节的序列的变长编码
3.5.4 字符串和byte切片
标准库中有四个包对字符串处理尤为重要
bytes;strconv包提供了布尔型、整数型、浮点数和对应字符串的相互转换,还提供了双引号转义相关的转换;unicode包用于给字符分类;strings包将原始字符串每个字符做相应的转换后返回新的新的字符串
字符串和slice之间可以相互转换
s:= "abc"
b:=[]byte(s)
s2 :=string(b)
3.5.5 字符串和数字的转换
x := 123
y := fmt.Sprintf("%d", x)
fmt.Println(y, strconv.Itoa(x)) //123 123
fmt.Println(strconv.FormatInt(int64(x), 2)) //1111011
x, err := strconv.Atoi("123")
y, err := strconv.ParseInt("123", 10, 64)
3.6 常量
每种常量的潜在类型都是基础类型,可以单个声明,也可以批量声明
const pi = 3.1415926
const (
e = 2.7182818284
pi = 3.1415926
)
常量运算后还是常量
3.6.1 iota常量生成器
const (
seven = iota//0
one//1
two//2
three//3
four//4
five//5
six//6
)
fmt.Println(five)//5
3.6.2 无类型常量
无类型的运算进度我们可以认为至少是256bit,六种未明确类型的常量类型:布尔型、整数、字符、浮点数、复数、字符串
math.Pi无类型的浮点数常量,可以直接用于任意需要浮点数或复数的地方
var x float32 = math.Pi
var y float64= math.Pi
var z complex128 =math.Pi
fmt.Println(x,y,z)//3.1415927 3.141592653589793 (3.141592653589793+0i)
对于常量面值,不同写法可能对应不同类型
只有常量有无类型