【Go语言学习笔记】类型、表达式

类型

变量

	var x int     // 自动初始化为0
	var y = false // 自动推断为bool类型
可以一次定义多个变量,包括用不同初始值定义不同类型
	var a, b int            // 相同类型的多个变量
	var c, d = 100, "hello" // 不同类型初始化值
简短模式
	x := 100
	a, s := 1, "abc"

限制:

  • 定义变量,同时显式初始化;
  • 不能提供数据类型;
  • 只能用在函数内部

= 和 := 的区别
= 是赋值,:= 是声明变量并赋值,并且系统自动推断类型,不需要var关键字

退化赋值

退化赋值的前提条件是:最少有一个新变量被定义,且必须是同一作用域

	x := 100
	println(&x, x)
	x, s := 200, "123"
	println(&x, x, s)

0xc000039f68 100    
0xc000039f68 200 123
// 对比内存地址,可以确认x属于同一变量 

// 无新变量被定义
	x := 100
	println(&x, x)
	x := 200
	println(&x, x)

no new variables on left side of :=

// 不同作用域
	x := 100
	println(&x, x)

	{
		x, s := 200, "hello"
		println(&x, x, s)
	}
0xc000039f68 100
0xc000039f60 200 hello

在处理函数错误返回值时,退化赋值允许重复使用err变量。

多变量赋值
	x, y := 1, 2
	x, y = y+3, x+2 // 先计算出右值 y+3, x+2 然后再对x、y变量赋值

命名

  • 以字母或者下划线开始,由多个字母、数字和下划线组合而成;
  • 区分大小写;
  • 使用驼峰拼写格式;
  • 局部变量优先使用短名;
  • 不要使用保留关键字;
  • 不建议使用与预定义常量、类型、内置函数相同的名字;
  • 专有名字通常会全部大写。
空标识符

空白标识符是未使用的值的占位符。它由下划线(_)表示。由于空白标识符没有名称,因此它们也被称为匿名占位符。

在 Go 语言中, 不允许声明未使用的变量或导入语句。也就是说,我们无法声明变量并将其留下未使用。同样,如果您导入一个包,那么也必须使用它。

这个时候就需要一个空白标识符。

如果 Go 中的函数返回多个值,则必须定义相等数量的变量来保存这些值。但是,如果您只需要其中一些值而不需要其他值,若某次赋值需要匹配多个左值,但其中某个变量不会被程序使用, 那么用空白标识符来代替。该变量可避免创建无用的变量,并能清楚地表明该值将被丢弃。

常量

常量表示运行时更定不可改变的值。

const x, y int = 123, 0x22

枚举

go中借助iota标识符实现一组自增常量值来实现枚举类型

const (
	x = iota // 0
	y        // 1
	z        // 2
)

const (
	_, _ = iota, iota * 2
	a, b
	c, d
)

如果中断iota自增,则必须显式回复,且后续自增值按行序号递增。

const (
	a = iota //0
	b        //1
	c = 100  //100
	d        //100
	e = iota //4
	f        //5
)

自增默认数据类型为int,可显式指定类型

const (
	a = iota         //0
	b                //1
	c = 100          //100
	d                //100
	e float32 = iota //+4.000000e+000
	f                //+5.000000e+000
)

常量和变量的不同

常量通常会被编译器在预处理阶段直接展开,作为指令数据使用。变量在运行期分配存储内存。数字常量不会分配存储空间,因此无法获取地址。

基本类型

类型长度默认值说明
bool1false
byte10
int,uint4,80默认证书类型,依据目标平台,32或64位
int8,uint810-128~127,0~255
int16,uint1620-32758~32767,0~65535
int32,uint3240-21亿~21亿,0~42亿
int64,uint6480
float3240.0
float6480.0默认浮点数类型
complex648
complex12816
rune40
uintptr4,80足以存储之战的uinit
string“”字符串,默认为空字符串而非null
array数组
struct结构体
functionnil函数
interfacenil接口
mapnil字典,引用类型
slicenil切片,引用类型
channelnil通道,引用类型

引用类型

reference type特值slice、map、channel这三种预定义类型。

应用类型必须使用make函数创建,编译器会将make转换为目标专用的创建函数,以确保完成全部内存分配和相关属性初始化。

func mkslice() []int {
	s := make([]int, 0, 10)
	s = append(s, 100)
	return s
}

func mkmap() map[string]int {
	m := make(map[string]int)
	m["a"] = 1
	return m
}

func main() {
	m := mkmap()
	println(m["a"])
	s := mkslice()
	println(s[0])
}

类型转换

除常量、别名类型以及未命名类型外,Go强制要求使用类型转换。

a:=10
b:=byte(a)
c:=a+int(b)

同时不能将非bool类型结果当作true/false使用

自定义类型

使用关键字type定义用户自定义类型,包括基于现有基础类型创建,或者是结构体、函数类型等。

	type ( //组
		user struct { // 结构体
			name string
			age  uint8
		}
		event func(string) bool // 函数类型
	)

	u := user{"Tome", 20}
	fmt.Println(u)

	var f event = func(s string) bool {
		println(s)
		return s != ""
	}
	f("abc")

自定义类型创建基础类型,也只能表明他们有相同地城数据结构,两者间不存在任何关系,属于完全不同的两种类型,自定义类型不会继承基础类型的其他信息,不能视作别名,不能隐式转换,不能直接用于比较表达式。

	type data int  // 自定义类型为基础类型
	var d data = 10
	var x int = d  // 不能隐式转换 Cannot use 'd' (type data) as the type int
	println(x) 
	println(d == x) // 两种完全不同的类型 Invalid operation: d == x (mismatched types data and int)

表达式

保留字

break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var

运算符

初始化

对于复合类型(数组、切片、字典、结构体)变量初始化时,有一些语法限制。

  • 初始化表达式必须含类型标签;
  • 左花括号必须在类型尾部,不能另起一行;
  • 多个成员初始值以逗号分隔;
  • 允许多行,但每行须以逗号或者右花括号结束。
	type data struct {
		x int
		y string
	}
	a := data{1, "hello"}
	b := data{
		1,
		"hello2",
	}
	c := []int{
		1,
		2}
	
	d:=[]int{1,2,
		3,4,
		5,
		}

流控制

if … else …

条件表达式值必须是布尔类型,可以省略括号,且左花括号不能另起一行。

	x := 3
	if x > 5 {
		println("a")
	} else if x < 5 && x > 0 {
		println("b")
	} else {
		println("c")
	}

支持初始化语句,可以定义块局部变量或者执行初始化函数。

    // 局部变量的有效范围包含整个if/else 块
    // 定义一个或多个局部变量,也可以是函数返回值
	if a, b := x+1, x+10; a < b {
		println(a)
	}
switch
	a, b, c, x := 1, 2, 3, 4
	switch x {
	case a, b: // 多个匹配条件命中其一即可OR
		println("a|b")
	case c:
		println("c")
	case 4: // 常量
		println("d")
	default:
		println(x)
	}

switch同样支持初始化语句,按从上到下、从左到右顺序匹配case执行。只有全部失败时,才会执行default块。

func main() {
	switch x := 5; x {
	default: //编译器确保不会先执行default块
		x += 100
		println(x)
	case 5:
		x += 50
		println(x)
	}
}

不能出现重复case常量值。

fallthrough 继续执行下一个case,但是不再匹配条件表达式,必须放在case块结尾,可以使用break语句阻止。

for
	for i := 0; i < 3; i++ { // 初始化表达式支持函数调用或定义局部变量
		
	}
	for x<10{  // 类似“while x<10 {} 或 for ;x<10;{}”
		x++
	}
	for{      // 类似“while true {} 或 for true {}”
		break
	}
for … range

可以使用for…range 完成数据迭代,支持字符串、数组、数组指针、切片、字典、通道,返回索引、键值数据。

	data := [3]string{"a", "b", "c"}
	for i, s := range data {
		println(i, s)
	}
	for i := range data {
		println(i, data[i]) // 只返回索引
	}
	for _, s := range data { // 忽略索引
		println(s)
	}
	for range data { // 仅迭代,可以用来执行清空channel等操作

	}

	for i, s := range data {
		println(&i, &s) // 局部变量重复使用
	}

	//0xc000039ec0 0xc000039f00
	//0xc000039ec0 0xc000039f00
	//0xc000039ec0 0xc000039f00

range会复制目标数据,受直接影响的是数组,可改用数组指针或者切片类型

	data := [3]int{10, 20, 30}
	for i, s := range data { // 从data 复制品中取值
		if i == 0 {
			data[0] += 100
			data[1] += 200
			data[2] += 300
		}
		fmt.Printf("s: %d, data: %d\n", s, data[i])
	}
s: 10, data: 110
s: 20, data: 220
s: 30, data: 330

	data := [3]int{10, 20, 30}
	for i, s := range data[:] { // 仅复制slice 不包括底层array
		if i == 0 {
			data[0] += 100
			data[1] += 200
			data[2] += 300
		}
		fmt.Printf("s: %d, data: %d\n", s, data[i])
	}
s: 10, data: 110
s: 220, data: 220
s: 330, data: 330
// 当i=0修改data时,s已经取值,所以是10 复制的仅是slice自身,底层array依旧是原对象

如果range目标表达式是函数调用,也仅被执行一次。

goto continue break

使用goto前,必须先定义标签,标签区分大小写,且未使用的标签会引发编译错误。而且不能跳转到其他函数,或者内层代码块内。配合标签,break和continue可在多层嵌套中指定目标层级。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值