go语言知识点 --主要针对与C++的区别
一、大括号与分号问题
分号跟在特定符号后面的换行符会被替换为分号,这会导致几个问题,说明如下:
- for、if 语句必须有大括号,独立语句也必须用大括号括起来。
if a:=1; a>0 {
a--;
}
if a==0 a++ // 编译失败
- "{" 必须和 for、if、func 等关键字在同一行,否则编译无法通过
if a:=1; a>0
{ // 编译失败
a--;
}
- else 必须与 if 的 } 在同一行,同: }else{
if a:=1; a>0{
a--;
}
else{ // 编译失败
}
二、格式化打印以及转义字符
- f系列函数支持格式化打印,包括:fmt.Printf,log.Printf, fmt.Errorf 等
- ln系列函数不含格式化串,但可以直接输出、添加空格、自动换行,如:fmt.println
- 转义符 %c 支持单独unicode汉字
- 转义符 %t 打印true/false串
- 转义符 %v 可以使用默认格式显示任意类型的值,如数组或map类型, 带[ ]
三、字符串操作
- 使用 + 可以为追加字符串,但是每次追加都会分配和释放内存
var s string
s += "aaa"
s = s + "bbb"
- 使用 strings.join 可以避免内存分配,提高效率
s := "hello"
fmt.Println(strings.Join([]string{s, "aaa", "bbb"}, ","))
// 输出:
// hello,aaa,bbb
strings.Join函数将数组中的成员一次性连接成sring,可以给出字符串之间的分割符。
- 与 strings.join 对应的是 strings.split
s := "hello,aaa,bbb"
ss := strings.Split(s, ",")
fmt.Println(ss)
// 输出:
// [hello aaa bbb]
四、函数或实体的声明
- 函数和其他包级别的实体可以以任意次序声明, 对函数的调用可以出现在其声明之前。
五、随机数生成器
GO语言1.20版本之后采用新的随机数生成器简化用法并提高安全性,避免了旧版本手动用时间播种时,在短时间内多次运行程序时,可能因时间戳相同导致随机序列重复。在 1.20 以前的go版本,生成随机数之前,会调用时间播种,然后获取随机数。
rand.Seed(time.Now().UTC().UnixNano())
fmt.Println(rand.Intn(100)) // 生成 0-99 的随机整数
fmt.Println(rand.Float64()) // 生成 0.0-1.0 的随机浮点数
从1.20版本开始,全局生成器会自动初始化,且每次程序运行都会生成不同的随机序列。用户在生成随机数之前无需播种,直接调用即可。
//rand.Seed(time.Now().UTC().UnixNano())
fmt.Println(rand.Intn(100)) // 生成 0-99 的随机整数
fmt.Println(rand.Float64()) // 生成 0.0-1.0 的随机浮点数
只有需要生成可复现随机数,才需要播种,但是需要创建一个新实例,而不是用全局的随机数生成器。自定义实例不会影响全局生成器的状态。
// 手动指定种子(如用时间戳,或固定值如 42 用于复现)
source := rand.NewSource(time.Now().UnixNano())
r := rand.New(source) // 创建自定义随机数生成器
// 使用自定义生成器生成随机数
fmt.Println(r.Intn(100))
fmt.Println(r.Float64())