常量
常量的值无法在运行时改变,一旦赋值过后就无法修改,其值只能来源于:
- 字面量
- 其他常量标识符
- 常量表达式
- 结果是常量的类型转换
- iota
常量只能是基本数据类型,不能是
- 除基本类型以外的其它类型,如结构体,接口,切片,数组等
- 函数的返回值
常量的声明需要用到const关键字,常量在声明时就必须初始化一个值,并且常量的类型可以省略。
iota是一个内置的常量标识符,通常用于表示一个常量声明中的无类型整数序数,一般都是在括号中使用。
常量的值无法被修改,如果尝试对其进行修改的话将会无法通过编译。
变量
变量是用于保存一个值的存储位置,允许其存储的值在运行时动态的变化。
声明
在go中的类型声明是后置的,变量的声明会用到var关键字,格式为var 变量名 类型名,变量名的命名规则必须遵守标识符的命名规则。
当要声明多个相同类型的变量时,可以只写一次类型
var numA, numB, numC int
当要声明多个不同类型的变量时,可以使用()进行包裹,可以存在多个()。
var (
name string
age int
address string
)
var (
school string
class int
)
一个变量如果只是声明而不赋值,那么变量存储的值就是对应类型的零值。
赋值
赋值会用到运算符=。
第二种方式每次都要指定类型,可以使用官方提供的语法糖:短变量初始化,可以省略掉var关键字和后置类型,具体是什么类型交给编译器自行推断。短变量初始化不能使用nil,因为nil不属于任何类型,编译器无法推断其类型。
name := "jack" // 字符串类型的变量。
name := nil // 无法通过编译
短变量声明方式无法对一个已存在的变量使用,但是有一种情况除外,那就是在赋值旧变量的同时声明一个新的变量。
// 错误示例
var a int
a := 1
// 错误示例
a := 1
a := 2
// 这种代码是可以通过编译的,变量a被重新赋值,而b是新声明的。
a := 1
a, b := 2, 2
在go语言中,有一个规则,那就是所有在函数中的变量都必须要被使用,代码只是声明了变量,但没有使用它,那么在编译时就会报错,提示变量声明了但没有使用。
这个规则仅适用于函数内的变量,对于函数外的包级变量则没有这个限制。
交换
在Go中,如果想要交换两个变量的值,不需要使用指针,可以使用赋值运算符直接进行交换。
比较
变量之间的比较有一个大前提,那就是它们之间的类型必须相同,go语言中不存在隐式类型转换。
在没有泛型之前,早期go提供的内置min,max函数只支持浮点数,到了1.21版本,go才终于将这两个内置函数用泛型重写。使用min函数比较最小值。
go中的可比较类型有
- 布尔
- 数字
- 字符串
- 指针
- 通道 (仅支持判断是否相等)
- 元素是可比较类型的数组(切片不可比较)
- 字段类型都是可比较类型的结构体(仅支持判断是否相等)
除此之外,还可以通过导入标准库cmp来判断,不过仅支持有序类型的参数,在go中内置的有序类型只有数字和字符串。
代码块
在函数内部,可以通过花括号建立一个代码块,代码块彼此之间的变量作用域是相互独立的。
块与块之间的变量相互独立,不受干扰,无法访问,但是会受到父块中的影响。
输入输出
在os包下有三个外暴露的文件描述符,其类型都是*File,分别是:
- Stdin - 标准输入
- Stdout - 标准输出
- Stderr - 标准错误
Go中的控制台输入输出都离不开它们。
输出
输出一句Hello 世界!,比较常用的有三种方法。
第一种是调用os.Stdout
os.Stdout.WriteString("Hello 世界!")
第二种是使用内置函数println
println("Hello 世界!")
第三种也是最推荐的一种就是调用fmt包下的Println函数
fmt.Println("Hello 世界!")
fmt.Println会用到反射,因此输出的内容通常更容易使人阅读,不过性能很差强人意。
格式化
0 | 格式化 | 描述 | 接收类型 |
1 | %% | 输出百分号% | 任意类型 |
2 | %s | 输出string/[] byte值 | string,[] byte |
3 | %q | 格式化字符串,输出的字符串两端有双引号"" | string,[] byte |
4 | %d | 输出十进制整型值 | 整型类型 |
5 | %f | 输出浮点数 | 浮点类型 |
6 | %e | 输出科学计数法形式 ,也可以用于复数 | 浮点类型 |
7 | %E | 与%e相同 | 浮点类型 |
8 | %g | 根据实际情况判断输出%f或者%e,会去掉多余的0 | 浮点类型 |
9 | %b | 输出整型的二进制表现形式 | 数字类型 |
10 | %#b | 输出二进制完整的表现形式 | 数字类型 |
11 | %o | 输出整型的八进制表示 | 整型 |
12 | %#o | 输出整型的完整八进制表示 | 整型 |
13 | %x | 输出整型的小写十六进制表示 | 数字类型 |
14 | %#x | 输出整型的完整小写十六进制表示 | 数字类型 |
15 | %X | 输出整型的大写十六进制表示 | 数字类型 |
16 | %#X | 输出整型的完整大写十六进制表示 | 数字类型 |
17 | %v | 输出值原本的形式,多用于数据结构的输出 | 任意类型 |
18 | %+v | 输出结构体时将加上字段名 | 任意类型 |
19 | %#v | 输出完整Go语法格式的值 | 任意类型 |
20 | %t | 输出布尔值 | 布尔类型 |
21 | %T | 输出值对应的Go语言类型值 | 任意类型 |
22 | %c | 输出Unicode码对应的字符 | int32 |
23 | %U | 输出字符对应的Unicode码 | rune,byte |
24 | %p | 输出指针所指向的地址 | 指针类型 |
使用fmt.Sprintf或者fmt.Printf来格式化字符串或者输出格式化字符串。
使用其它进制时,在%与格式化动词之间加上一个空格便可以达到分隔符的效果。在使用数字时,还可以自动补零。
错误情况
格式化字符数量 < 参数列表数量
fmt.Printf("", "") //%!(EXTRA string=)
格式化字符数量 > 参数列表数量
fmt.Printf("%s%s", "") //%!s(MISSING)
类型不匹配
fmt.Printf("%s", 1) //%!s(int=1)
缺少格式化动词
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)
输入
输入的话是通常使用fmt包下提供的三个函数
// 扫描从os.Stdin读入的文本,根据空格分隔,换行也被当作空格
func Scan(a ...any) (n int, err error)
// 与Scan类似,但是遇到换行停止扫描
func Scanln(a ...any) (n int, err error)
// 根据格式化的字符串扫描
func Scanf(format string, a ...any) (n int, err error)
需要注意的是,Go中输入的默认分隔符号是空格。
缓冲
当对性能有要求时可以使用bufio包进行读取。
文章评论