跳至主要內容

泛操作

LincZero大约 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. 其他运算符
&, *

优先级:(越靠前越优先,反正我也懒得记,不常用不记得的就加括号)

分类运算符结合性
后缀运算符 (伪单目)()、[]、->从左到右
单目运算符从右到左
算数运算符 (乘除取余 > 加减)从左到右
位移运算符从左到右
关系运算符从左到右
相等/不相等从左到右
按位运算 (与 > 异或 > 或)从左到右
逻辑运算符 (与 > 或,非归类到单目)从左到右
赋值运算符从右到左
逗号运算符从左到右