- 内建类型的使用
- 变量与常量的使用以及惯例
写一些代码,看一看如何"最好"的运用他们,关于什么是“最好”,这里有一个最主要的原则:让你的意图能够透过代码清晰的表示出来
内建类型 Built-in Types
惯用法是跨语言使用者的障碍,学一门新的编程语言,主要是向这个方向靠拢(可通过开源代码和 ChatGPT 解决)
分配一个默认的 zero value 到所有已声明但未赋值变量是 Go 的特点
字面量 Literals
四种字面量:整型,浮点,字符,字符串
整型字面量的表示:
121 // 普通十进制数
0xAD // 十六进制
0o17 // 也可以 0 开头,但不建议
0b101 // 二进制
1_234 // 下划线无特殊作用,只是让 coder 读数字更轻松一些,千分位或者8bit 1,000,000 -> 1_000_000; 0xAA -> 0b1010_1010
1_2_3_4
浮点型字面量:
2.2e2 // 220 指数指定小写e
2.2e-2 // 0.022 指数指定小写e
0.321_33_2 // 0.321332 下划线无特殊作用,仅用作提升写代码人的可读性
字符 Rune
'a'
'\142'
'\x21'
'\u0022'
'\U00000001'
'\n'
'\t'
'\\'
字符串 String
"Hello World" // double quotes
`Hello "World"` // raw string literal
如果两个整型变量size不一致,是无法相加的
但是整型字面量可以用到浮点表达式当中,也可以分配一个整型字面量到浮点型变量中
因为字面量是 untyped 的,可以提高代码编写的灵活性,不对字面量作强制类型要求
如果分配的字面量超出了变量的类型上限,会引起编译时错误
在某些情况,没有在表达式中明确指定类型的字面量,会为字面量使用一个 default type
布尔 Booleans
var foobar bool // default `zero value` is `false`
数字 Numeric Types
Go 3 类 12 种
整型 Integer
类型 | alias | range |
---|---|---|
int8 | -27~27-1 | |
int16 | -215~215-1 | |
int32 | rune, (uint, int if 32-bit CPU) | -231~231-1 |
int64 | (uint, int if 64-bit CPU) | -263~263-1 |
uint8 | byte | 0~2^8-1 |
uint16 | 0~2^16-1 | |
uint32 | 0~2^32-1 | |
uint64 | 0~2^64-1 |
相比其他语言提供了丰富的整型类型
设计函数库的一种模式:
Go 标准库中有很多使用int64
以及uint64
编写的函数ParseInt/ParseUint
,用户在使用的时候自行转换类型即可,这样就不用为每一种类型分别编写函数,因为 Go 暂时不支持重载 generics
一个关于整型类型使用技巧是:不要过早优化,总是使用 int
,除非被明显证明不可行
算术操作符
+ - * / %
+= -= *= /= %=
逻辑符号
== != > >= < <=
比特操作符
<< >> & | ^ &^
<<= >>= &= |= ^= &^=
浮点型 Float Number
类型 | alias | range |
---|---|---|
float32 | -231~231-1 | |
float64 | -263~263-1 | |
总是使用 float64,除非你必须去兼容一个已存在的格式 | ||
浮点字面量默认为 float64 | ||
float32 只有 6 或者 7 位表示小数 | ||
不要过早担心内存占用问题,除非你使用 profiler 检测出这是一个需要认真对待的决策 | ||
与其他语言一样,浮点数因为精确度问题不能用于做定点数做的工作,在涉及精确的金额问题的时候最好转换为定点数(浮点数多用于图形图像和科学计算) | ||
浮点数的存储标准 IEEE_754 | ||
因为不精确 inexact 特性,不建议使用 == 或者 != 比较浮点数,给出一个区间然后用 > < 是比较好的做法 |
复数 Complex types
skip
字符与字符串
与 Java 不同,字符串是作为 Go 的内建类型而存在的,Go 的目的就是为了解决网络应用程序开发的效率问题,而整个网络中处理,传输最多的就是字符串。
字符串不可变,不可变的意思是只能被一整块的重新分配到内存,而不可以修改字符串在内存中的比特位
码点 code point,rune 是 int32 的别名
明确的类型转换
忘记掉自动类型转换规则
Go 不处理类型提升,必须由 coder 亲自转换类型后再处理,不同 size 的整型和浮点型也不行,必须明确的手动的进行类型转换
如果你使用多个编程语言协同工作,其实这是一个好事,不用记住每种编程语言的转换特点。
变量
var foo int = 10
var bar = 20
xyz := 30
var x int
var x,y int = 10, 20
var x, y, z float64 // zero value
var x, y = 22, "Hello World"
var (
x int
y float64
)
区别
var
可以在 package
级别使用,:=
只能在 function
作用域使用
使用技巧
初始化为 zero value 不需要使用 :=
,直接使用 var
就行,比如
x := 0 // ❌
var x int // ✔️
仅仅靠字面量不足以推导你想要的类型的时候使用 var
#include <stdio.h>
// 有的语言可以在字面量上追加修饰符来指明类型 `10L`, `20LL`, `10D`
int main() {
printf("%ld", 10L);
return 0;
}
但是 Go 中没有这种操作,所以可以使用 var
来解决字面量缺乏类型的问题
x := byte(20) // ❌
var x byte = 20 // ✔️
需要在代码上下文中明确区分新变量
与旧变量
的时候使用 var
(因为 :=
具有隐式重新赋值的能力 reassign)
你不应该经常在包作用域 package scope 下声明变量并变动它的值,主要是基于调试跟踪困难来考虑,因为数据流穿梭于整个包作用域下,跟踪打断点比较麻烦。
包变量按常量方式使用是可接受的
常量 const
常量在 Go 中是一种给字面量起名字的方式,没有办法确保值完全不被修改
像 array,slices,maps,常量引用的只是一个地址,地址内的内容并不受控制
const x int = 10
const (
a = 1
b = "hello"
)
const foo = 60 * 60 * 24
func main() {
const x = 10
}
常量类型的问题
const x = 100 // 这是一个无类型的常量
var y int = x // ✔️
var z float64 = x // ✔️
var d byte = x // ✔️
const y int = 100 // 这是一个有类型的常量
var g float64 = y // ❌
未使用的变量会被在编译时检查,每一个声明的 local 变量必须被至少取值过一次
常量没有限制,未被使用的常量不会出现在二进制文件中
变量命名的约定
字母与下划线数字都是可以的
idiomatic Go doesn’t use snake case
小驼峰是 Go 的惯用样式
下划线本身也是一个特别的标识符,通常用于函数返回值的 ignore 处理
Go 不使用大写字母下划线组合的常量,因为包级别的声明下,大写开头的变量函数可以被外部访问
函数内部偏好短变量名,作用域越小,变量名越短是一个惯例,单字母变量名是很常见的
函数外部 package level 变量名尽可能详尽一些,关于变量命名规则可以查看 关于代码风格的规范
Go 不在变量名中体现变量类型(匈牙利命名法)