泛操作
大约 4 分钟
泛操作
变量
内存中的一个数据存储表示
声明定义、赋值、使用
由于有 默认初始化,这里不区分 声明与定义
main.go
package main
import "fmt"
func main() {
var age int // 变量声明
age = 18 // 变量赋值
fmt.Println("age = ", age) // 变量使用
var age2 int = 18; // 变量的声明和赋值可以合在一起
}
其他语法糖或特性
main.go
var num1 int = 18 // 声明并赋值
fmt.Println(num1)
var num2 int // 自动初始化
fmt.Println(num2)
var str1 = "18" // 自动类型推导
fmt.Println(str1)
str2 := "hello" // 省略var,注意不能忽略冒号
fmt.Println(str2)
var n1, n2, n3 int // 多个变量声明
var n4, n5, n6 = 10, "jack", 7.8
n7, n8 := 10, "duck"
全局与局部变量
package main
import( // 批量声明的语法糖 (引入)
"fmt"
"unsafe"
)
var n1 int = 0 // 全局变量
var ( // 批量声明的语法糖 (类型声明)
n9 = 500
n10 = "netty"
)
func main() {
var n2 int = 1 // 局部变量
}
个人吐槽:
说好的语言特点是只有一种写法,但写法有的是比其他语言少……而有的语法糖反而比其他语言还多了……。少掉的东西中:
部分是像 编译强制初始化这种是更根本的东西,
但大部分则是一些换行和空格这种仅编码风格的约束。有种设计者强制所有人共用同一个
.clang-format
或者eslint
,且不符合则不给编译通过,的这种感觉。 符合我平时的写法我会觉得早该这么做了,否则我就感觉设计者闲得蛋疼,加这种约束闲得没事干)
下面是更详细的补充:
自动初始化
复习下:
与其他语言不同:
- 有默认初始化
- Java / Kotlin / Python / Swift / Go
- 基本类型:默认初始化为零值
- 对象引用:默认初始化为空 (java为null,kotlin为null,python为None,swift为nil,go为nil)
- TypeScript/JavaScript:
- 默认初始化为 undefined
- 强制初始化
- Rust
- 强制初始化,否则报错,不存在默认初始化的行为
- 无默认初始化
- C/C++(这一类就只有C/C++了,hhhh)
- 基本类型:无默认初始化,成员变量也是。使用这些变量是未定义行为,且无物理内存及虚拟内存对应的值是随机的
- 全局变量/静态变量:默认初始化为零值
Go的默认值:
数据类型 | 默认值 |
---|---|
整数类型 | 0 |
浮点类型 | 0.0 |
布尔类型 | false |
字符串类型 | "" |
自动类型推导
与其他语言不同:
更类似于typescript语言,像C++是需要用auto关键字的
初始化检查
var n1 int8 = 2.3 // 编译错误,类型不符
var n2 int8 = int12 + 128 // 编译错误,超出界限
省略var写法 (:= 写法)
批量声明写法
类型转换
Go只有强制转换,没有隐式转换,哪怕小类型转大类型。
语法上 T(v) 就可以了,和其他语言类似,也会出现类型缩窄
数字类型转化
var n1 int = 100
var n2 float32 = n1 // 报错
var n2 float32 = float32(n1) // 正确
var n5 int32 = 12
var n6 int64 = n5 + 30 // 报错
var n6 int64 = int64(n5) + 30 // 正确
数值与string 互相转化
(字符串转化相关,详见 “模块库/字符串库”)
类/接口的互转
派生类转基类不需要额外转换,里氏替换原则。基类转派生类则需要类型转换。
同理,类转接口类型不需要额外转换,反过来则需要使用类型断言:
// 通用语法
// value:变量的值
// ok:book类型
// element:interface变量
// T:断言类型
value, ok = element.(T)
// 举例。将人转中国人
chinese, flag = person.(Chinese)
类型/占用内存打印
package main
import "fmt"
import "unsafe"
func main(){
var num3 = 28
fmt.Printf("num3的类型是 %T", num3) // int
fmt.Println(unsafe.Sizeof(num3)) // 8 (Byte)
}
运算符
与其他语言不同:
- Go的整除是向零而非向下取整
- 极大限制了C/C++/Java的++/--骚操作,只能单独一个表达式使用,且只能放在变量后面 (个人吐槽:对于学生来说好耶,但老程序员感觉这不是很爽)
几乎和其他语言一样,这里没有三目运算符
// 1. 算数运算符
+, -, *, /, %, ++, -- // 相同点:整数除法也是整除,也有逻辑运算符也有短路
// 2. 赋值运算符
=, +=, -=, *=, /=, %=
// 3. 关系运算符
==, !=, <, >, <=, >=
// 4. 逻辑运算符
&&, ||, !
// 5. 位运算符
&, |, ^
// 6. 其他运算符
&, *
优先级:(越靠前越优先,反正我也懒得记,不常用不记得的就加括号)
分类 | 运算符 | 结合性 |
---|---|---|
后缀运算符 (伪单目) | ()、[]、-> | 从左到右 |
单目运算符 | 从右到左 | |
算数运算符 (乘除取余 > 加减) | 从左到右 | |
位移运算符 | 从左到右 | |
关系运算符 | 从左到右 | |
相等/不相等 | 从左到右 | |
按位运算 (与 > 异或 > 或) | 从左到右 | |
逻辑运算符 (与 > 或,非归类到单目) | 从左到右 | |
赋值运算符 | 从右到左 | |
逗号运算符 | 从左到右 |