Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

My Blog

从此烟雨落金城,一人撑伞两人行。

第四章(下):基本数据类型

常量

常量使用关键字 const 定义,用于存储不会改变的数据。

存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

1
const Pi = 3.14

常量的值必须是能够在编译时就能够确定的。

因为在编译期间自定义函数均属于未知,因此无法用于常量的赋值,但内置函数可以使用,如:len()。

1
2
const Ln2 = 0.693147180559945309417232121458\
176568075500134360255254120680009

反斜杠 \ 可以在常量表达式中作为多行的连接符使用。

常量并行赋值

1
const beef,two,c = "eat",2,"vag"

iota 可以被用作枚举值:

1
2
3
4
5
const (
a = iota
b = iota
c = iota
)

简单地讲,每遇到一次 const 关键字,iota 就重置为 0。.

变量

声明变量的一般形式是使用 var 关键字:var identifier type

1
2
3
4
5
6
7
8
9
var a int
var b bool
var str string

var (
a int
b bool
str string
)

变量的命名规则遵循骆驼命名法。

全局变量希望能够被外部包所使用,则需要将首个单词的首字母也大写。

变量可以编译期间就被赋值,赋值给变量使用运算符等号 =,可以在运行时对变量进行赋值操作。

1
2
3
4
5
var a int
var b bool

a = 15
b = true

声明与赋值(初始化)语句也可以组合起来。

1
2
var a int = 15
var b bool = false

自动类型推断

1
2
3
4
5
6
7
8
9
10
var a = 15
var b = false

var (
a = 15
b = false
str = "Go says hello to the world!"
numShips = 50
city string
)

在函数体内声明局部变量时,应使用简短声明语法 :=,例如:

1
a := 1

实例:

1
2
3
4
5
6
7
8
9
10
11
12
package main
import (
"fmt"
"runtime"
"os"
)
func main (){
goos := runtime.GOOS
fmt.Printf("%s\n",goos)
var path string = os.Getenv("PATH")
fmt.Printf("%s\n",path)
}

值类型和引用类型

int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值。

数组和结构体这些复合类型是值类型。

指针、切片、映射和通道是引用类型。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。

函数 fmt.SprintfPrintf 的作用是完全相同的,不过前者将格式化后的字符串以返回值的形式返回给调用者。

在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的。

1
a, b, c := 5, 7, "abc"

交换两个变量的值,则可以简单地使用 a, b = b, a

init函数

变量除了可以在全局声明中初始化,也可以在 init 函数中初始化。

每个源文件都只能包含一个 init 函数。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。

用途是在开始执行程序之前对数据进行检验或修复,以保证程序状态的正确性。

1
2
3
4
5
6
package trans
import "math"
var Pi float64
func init(){
Pi = 4*math.Atan(1)
}
1
2
3
4
5
6
7
8
9
package main
import (
"fmt"
"./trans"
)
var twoPi = 2*trams.Pi
func main(){
fmt.Printf(twoPi)
}

init 函数也经常被用在当一个程序开始之前调用后台执行的 goroutine。

1
2
3
4
func init() {
// setup preparations
go backend()
}

基本类型与运算符

bool类型

只有两个类型相同的值才可以进行比较,如果值的类型是接口,它们也必须都实现了相同的接口。

布尔型的常量和变量也可以通过和逻辑运算符(非 !、和 &&、或 ||)结合来产生另外一个布尔值。

非运算符用于取得和布尔值相反的结果。

&&两边的值都为 true 的时候,结果才是 true。

||两边的值都为 false 的时候,结果才是 false。

在格式化输出时,你可以使用 %t 来表示你要输出的值为布尔型。

数字类型

Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。

Go 也有基于架构的类型,例如:int、uint 和 uintptr。

这些类型的长度都是根据运行程序所在的操作系统类型所决定的:

  • intuint 在 32 位操作系统上,它们均使用 32 位(4 个字节),在 64 位操作系统上,它们均使用 64 位(8 个字节)。
  • uintptr 的长度被设定为足够存放一个指针即可。

Go 语言中没有 float 类型。(Go语言中只有 float32 和 float64)没有double类型。

int 型是计算最快的一种类型。

float32 精确到小数点后 7 位,float64 精确到小数点后 15 位。

尽可能地使用 float64,因为 math 包中所有有关数学运算的函数都会要求接收这个类型。

前缀 0 来表示 8 进制数(如:077),增加前缀 0x 来表示 16 进制数(如:0xFF),以及使用 e 来表示 10 的连乘(如: 1e3 = 1000,或者 6.022e23 = 6.022 x 1e23)。

可以使用 a := uint64(0) 来同时完成类型转换和赋值操作,这样 a 的类型就是 uint64。

Go 中不允许不同类型之间的混合使用,但是对于常量的类型限制非常少,因此允许常量之间的混合使用:

1
2
3
4
5
6
7
8
package main
func main(){
var a int
var b int32
a = 15
b = a+a //编译错误
b = b+5 //5是常量,可以编译
}

格式化说明符

%d 用于格式化整数(%x%X 用于格式化 16 进制表示的数字),%g 用于格式化浮点型(%f 输出浮点数,%e 输出科学计数表示法),%0nd 用于规定输出长度为n的整数,其中开头的数字 0 是必须的。

%n.mg 用于表示数字 n 并精确到小数点后 m 位,除了使用 g 之外,还可以使用 e 或者 f,例如:使用格式化字符串 %5.2e 来输出 3.4 的结果为 3.40e+00

/ 对于整数运算而言,结果依旧为整数,例如:9 / 4 -> 2

取余运算符只能作用于整数:9 % 4 -> 1

对于整数和浮点数,你可以使用一元运算符 ++(递增)和 --(递减),但只能用于后缀。

++-- 的只能作为语句,而非表达式,因此 n = i++ 这种写法是无效的。

随机数

rand 包实现了伪随机数的生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
for i:=0; i<5; i++{
a := rand.Int()
fmt.Printf("%d\n",r)
}
for i := 0; i < 5; i++ {
r := rand.Intn(8)
fmt.Printf("%d / ", r)
}
times := int64(time.Now().Nanosecond())
rand.Seed(times)
for i := 0; i < 10; i++ {
fmt.Printf("%2.2f / ", 100*rand.Float32())
}
}

函数 rand.Intn 返回介于 [0, n) 之间的伪随机数。

类型别名

type TZ int 中,TZ 就是 int 类型的新名称(用于表示程序中的时区),然后就可以使用 TZ 来操作 int 类型的数据。

新类型不会拥有原类型所附带的方法。

字符类型

byte 类型是 uint8 的别名。

Go 同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,并在内存中使用 int 来表示。

rune 也是 Go 当中的一个类型,并且是 int32 的别名。

1
var ch byte = 65var ch byte = '\x41'

var ch byte = 'A';字符使用单引号括起来。

Unicode 至少占用 2 个字节,所以我们使用 int16 或者 int 类型来表示。如果需要使用到 4 字节,则会加上 \U 前缀;前缀 \u 则总是紧跟着长度为 4 的 16 进制数,前缀 \U 紧跟着长度为 8 的 16 进制数。

1
2
3
4
5
6
7
8
9
10
11
12
var ch int = '\u0041'
var ch2 int = '\u03B2'
var ch3 int = '\U00101234'
fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer
fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character
fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes
fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point

65 - 946 - 1053236
A - β - r
41 - 3B2 - 101234
U+0041 - U+03B2 - U+101234
  • 判断是否为字母:unicode.IsLetter(ch)
  • 判断是否为数字:unicode.IsDigit(ch)
  • 判断是否为空白符号:unicode.IsSpace(ch)

utf8 拥有更多与 rune 类型相关的函数。

字符串

字符串是一种值类型,且值不可变,字符串是字节的定长数组。

Go 中的字符串是根据长度限定,而非特殊字符\0

函数 len() 来获取字符串所占的字节长度。

在循环中使用加号 + 拼接字符串并不是最高效的做法,更好的办法是使用函数 strings.Join()。

使用字节缓冲(bytes.Buffer)拼接更加给力。

strings和strconv包

Go 中使用 strings 包来完成对字符串的主要操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
strings.HasPrefix(s, prefix string) bool
// 判断字符串 s 是否以 prefix 开头

strings.HasSuffix(s, suffix string) bool
// 判断字符串 s 是否以 suffix 结尾

strings.Contains(s, substr string) bool
// 判断字符串 s 是否包含 substr

strings.Index(s, str string) int
// Index 返回字符串 str 在字符串 s 中的索引
strings.LastIndex(s, str string) int
// LastIndex 返回字符串 str 在字符串 s 中最后出现位置的索引
strings.IndexRune(s string, r rune) int
// 非 ASCII 编码的字符在父字符串中的位置

strings.Replace(str, old, new, n) string
// Replace 用于将字符串 str 中的前 n 个字符串 old 替换为字符串 new,并返回一个新的字符串,如果 n = -1 则替换所有字符串 old 为字符串 new

strings.Count(s, str string) int
// Count 用于计算字符串 str 在字符串 s 中出现的非重叠次数

strings.Repeat(s, count int) string
// Repeat 用于重复 count 次字符串 s 并返回一个新的字符串

strings.TrimSpace(s) 来剔除字符串开头和结尾的空白符号;如果你想要剔除指定字符,则可以使用 strings.Trim(s, "cut") 来将开头和结尾的 cut 去除掉。

strings.Split(s, sep) 用于自定义分割符号来对指定字符串进行分割,同样返回 slice。

strings.Join(sl []string, sep string) string
// Join 用于将元素类型为 string 的 slice 使用分割符号来拼接组成一个字符串

与字符串相关的类型转换都是通过 strconv 包实现的。

1
2
3
4
5
6
7
8
9
10
strconv.Itoa(i int) string
// 返回数字 i 所表示的字符串类型的十进制数。

strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string
// 将 64 位浮点型的数字转换为字符串

strconv.Atoi(s string) (i int, err error)
// 将字符串转换为 int 型。

strconv.ParseFloat(s string, bitSize int) (f float64, err error) // 将字符串转换为 float64 型。

评论