Go - Task3 - 变量, 常量, 枚举

本文详细介绍了Go语言中的变量、常量和枚举的使用。对于变量,包括简短变量声明、指针以及new函数的用法,并探讨了Go的垃圾回收机制。常量部分讲解了其定义方式。枚举部分则展示了如何利用iota实现枚举,并分析了枚举的使用场景和限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Task3 - 变量, 常量, 枚举

typeora放到csdn上好丑= =
参考:

变量

  • 格式

    •   var 变量名 类型 = 表达式
      
  • 类型 / 表达式 两个部分可以省略一个

    • 省略表达式, 那么变量将给据类型来进行默认赋值
      • 数值: 0
      • 布尔: false
      • 字符串: “”
      • 接口/引用类型: nil
      • 数组/结构体等聚合类型对应的0值为每个元素都是其对应该类型的0值
    • 省略类型, 那么变量将会根据初始化的表达式来推导变量的类型
    • 零值的初始化机制可以确保每个声明的变量总有一个良好的初始化定义值

简短变量声明

  • 格式

    •   名字 := 表达式
      
  • 变量的类型根据表达式来自动推导

package main
import "fmt"
func main(){
	var s string
	fmt.Println("s=", s)
	var i, j int				// 隐藏表达式
	var n, m = 5, 5             // 隐藏类型
	for ; i < n; i++ {
		for k := i; k < m; k++ {// 简短变量声明
			fmt.Print(j)
		}
		fmt.Println()
	}
}
// output
c:\UserData\Go\Begin\Test>go run Task2.go
s=
00000
0000
000
00
0
  • var形式的声明语句往往是用于需要显式指定变量类型的地方/因为变量稍后会被重新赋值儿初始值无关紧要
var err error
var strs []string
fmt.Println("err:", err)     // err: <nil>
fmt.Println("strs:", strs)   // strs: []

“:=”是一个变量声明语句,而“=”是一个变量赋值操作。也不要混淆多个变量的声明和元组的多重赋值(§2.4.1),后者是将右边各个表达式的值赋值给左边对应位置的各个变量:

i, j = j, i // 交换 i 和 j 的值
  • 简短变量声明语句中必须至少要声明一个新的变量(可以混合已声明和未声明的变量, 但不能都是已声明, 否则会编译错误)
f, err := os.Open(infile)
// ...
f, err := os.Create(outfile) // compile error: no new variables

指针

  • 感觉类似于c语言的指针
  • &x 表示取变量x的内存地址, 产生一个指向该变量x的指针, 对应的数据类型未int*(假设x为int)
x := 1
posX := &x
fmt.Println(*posX)
*posX = 2
fmt.Println(x)
  • 对调用函数内部的指针在函数结束后返回仍然安全
    • 因为指针p仍然引用这个变量, 所以局部变量还是安全的
var p = f()

func f() *int {
	v := 1
	return &v
}

每次我们对一个变量取地址,或者复制指针,我们都是为原变量创建了新的别名。例如,*p就是变量v的别名。指针特别有价值的地方在于我们可以不用名字而访问一个变量,但是这是一把双刃剑:要找到一个变量的所有访问者并不容易,我们必须知道变量全部的别名(译注:这是Go语言的垃圾回收器所做的工作)。不仅仅是指针会创建别名,很多其他引用类型也会创建别名,例如slice、map和chan,甚至结构体、数组和接口都会创建所引用变量的别名。

new函数

另一个创建变量的方法是调用内建的new函数。表达式new(T)将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址,返回的指针类型为*T

p := new(int)   // p, *int 类型, 指向匿名的 int 变量
fmt.Println(*p) // "0"
*p = 2          // 设置 int 匿名变量的值为 2
fmt.Println(*p) // "2"

Go的回收机制(变量的生命周期)

  • 讲解的很清晰Orz, 直接粘贴了

基本的实现思路是,从每个包级的变量和每个当前运行函数的每一个局部变量开始,通过指针或引用的访问路径遍历,是否可以找到该变量。如果不存在这样的访问路径,那么说明该变量是不可达的,也就是说它是否存在并不会影响程序后续的计算结果。

因为一个变量的有效周期只取决于是否可达,因此一个循环迭代内部的局部变量的生命周期可能超出其局部作用域。同时,局部变量可能在函数返回之后依然存在。

编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,但可能令人惊讶的是,这个选择并不是由用var还是new声明变量的方式决定的。

常量

  • 常量是一个简单值的标识符,在程序运行时,不会被修改的量。数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。 常量的定义格式:(省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。)
const identifier [type] = value
const b = "abc"

多个相同类型的声明可以简写为:

const c_name1, c_name2 = value1, value2

常用于枚举:

const (
  Unknown = 0
  Female = 1
  Male = 2
)
0,1,2 代表未知、女、男

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过。

iota,特殊常量,可认为是可以被编译器修改的常量。在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;

package main

import "fmt"
const (
  i=1<<iota
  j=3<<iota
  k
  l
)

func main() {
  fmt.Println("i=",i)
  fmt.Println("j=",j)
  fmt.Println("k=",k)
  fmt.Println("l=",l)
}
结果:
i= 1
j= 6
k= 12
l= 24

枚举

枚举,将变量的值一一列举出来,变量只限于列举出来的值的范围内取值。Go语言中没有枚举这种数据类型的,但是可以使用const配合iota模式来实现

普通枚举

const (
	a = 0
	b = 1
	c = 2
	d = 3
)

自增枚举

  1. iota只能用于常量表达式
  2. 它默认开始值是0,const中每增加一行加1,同行值相同
const (
	a = iota //0
	c        //1
	d        //2
)
const (
	e, f = iota, iota //e=0, f=0
	g    = iota       //g=1
)
  1. 若中间中断iota,必须显式恢复。
const (
  a = iota    //0
  b           //1
  c = 100     //100
  d           //100
  e = iota    //4
  f           //5
  g           //6  这里恢复后仍然可以保证为自增枚举
)

(但是u1s1如果只能从1开始赋值的话 感觉这个枚举似乎作用不是很大?, 可能能改参数使得枚举赋值调整?)

  • 还可以使用iota结合运算符
const (
	a = iota * 2
	b
	c
	d
	e
)

0 2 4 6 8 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值