(2-2)基础语法:常量和变量

2.3  常量和变量

在Go语言中,可以将基本的数据类型分为两种:常量和变量。在程序执行过程中,其值不发生变化的数据类型被称为常量,其值可以变化的被称为变量。

2.3.1  常量

在Go语言中,常量和变量的区别如下:

  1. 常量的意志比较坚定,一旦定义一个值后就永远不会变。
  2. 变量的立场不坚定,在程序的运行过程中可能会发生变化。

在Go中使用关键字const定义常量,并且经常用大写字母表示常量名。例如,在下面的代码中,定义了一个名为“RICE”的常量:

const PRICE int = 10

通过上述代码,将常量“RICE”的值设置为整数10。并且在整个程序中,整数10这个值是一直固定不变的。

读者需要注意的是,Go语言和许多编程语言不同,它在声明变量时将变量的类型放在变量的名称之后。这样做的好处就是可以避免像C语言中那样含糊不清的声明形式,例如:int* a, b; 。其中只有 a 是指针而 b 不是。如果你想要这两个变量都是指针,则需要将它们分开书写。

实例2-1:打印输出某学生的考试成绩(源码路径:Go-codes\2\exam.go

实例文件exam.go的具体实现代码如下所示。

package main
import "fmt"
func main() {
	const SCORE int = 100
	fmt.Println("你的期末考试成绩为:", SCORE)
}

在上述代码中,首先创建了整型常量SCOR并赋值为100,然后使用函数println()打印输出成绩。执行后会输出:

你的期末考试成绩为:100

在Go语言中有一个特殊常量:iota,这是一个可以被编译器修改的常量。iota在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

2.3.2  变量的声明

在Go语言中,将其值可以改变的量称为变量。一个变量应该有一个名字,并在内存中占据一定的存储单元。必须将变量定义放在变量被使用之前,一般放在函数体的开头部分。

注意:任何一种编程语言都离不开变量,特别是在数据处理程序中。我们甚至无法编写出没有变量参与的程序,即使能编写出来,这样的程序也没有意义。变量之所以如此重要,是因为变量是编程语言中数据的符号标识和载体。变量是内存或寄存器中用一个标识符命名的存储单元,可以用来存储一个特定类型的数据,并且数据的值在程序运行过程中可以进行修改。程序员一旦定义了变量,那么,变量至少可为我们提供两个信息:一是变量的地址,即操作系统为变量在内存中分配的若干内存的首地址;二是变量的值,也就是变量在内存中所分配的那些内存单元中所存放的数据。

在Go程序中,声明变量的语法格式如下。

var name type
  1. var:是声明变量的关键字;
  2. name:是变量名;
  3. type:是变量的类型。

当一个变量被声明之后,系统自动赋予它该类型的零值:int类型的初始值为 0,float类型的初始值为 0.0,bool类型的初始值为 false,string类型的初始值为空字符串,指针类型的初始值为 nil 等。所有的内存在 Go 中都是经过初始化的。

如果大家觉得觉得每行都用 var 声明变量比较烦琐,可以使用如下批量声明变量的方法:

var (
    a int
    b string
    c []float32
    d func() bool
    e struct {
    x int
    }
)

在上述声明格式中,在Go程序中还可以使用如下更加简短的变量声明和初始化语法。

名字 := 表达式

需要注意的是,在使用上述简短模式(short variable declaration)有以下限制:

  1. 声明变量,同时显式初始化。
  2. 不能提供数据类型。
  3. 只能用在函数内部。

和使用关键字var声明变量的语句一样,简短变量声明语句也可以用来声明和初始化一组变量。例如:

i, j := 0, 1

下面通过一段代码来演示简短格式变量声明的基本样式。

func main() {
   x:=100
   a,s:=1, "abc"
}

在上述代码的第3行代码中,使用简短方式同时声明了变量a和s。

注意:因为简洁和灵活的特点,简短变量声明被广泛用于大部分的局部变量的声明和初始化。var 形式的声明语句往往是用于需要显式指定变量类型地方,或者因为变量稍后会被重新赋值而初始值无关紧要的地方。

2.3.3  变量的初始化

在Go语言中声明变量时,会自动对变量对应的内存区域进行初始化操作。每个变量会初始化其类型的默认值,例如整型和浮点型变量的默认值为 0 和 0.0,字符串变量的默认值为空字符串,等等。当然,我们也可以在变量声明时给变量设置一个初始值。实现变量初始化的语法格式如下:

var 变量名 类型 = 表达式

请看下面的代码,hp 为变量名,类型为 int,hp 的初始值为 100。

var hp int = 100

在上面的代码中,100 和 int 同为 int 类型,int 可以认为是冗余信息,因此可以进一步简化初始化的写法。我们可以将 int省略:

var hp = 100

这样编译器会尝试根据等号右边的表达式推导 hp 变量的类型,等号右边的部分在编译原理里被称做右值(rvalue)。

实例2-2:根据右值推导变量类型完成初始化(源码路径:Go-codes\2\tui.go

实例文件tui.go的具体实现代码如下所示。

package main
import "fmt"
func main(){
	var attack = 40
	var defence = 20
	var damageRate float32 = 0.17
	var damage = float32(attack-defence) * damageRate
	fmt.Println(damage)
}

对上述代码的具体说明如下:

  1. 第 4和 5行:右值为整型,变量attack 和 defence的类型为 int。
  2. 第 6 行:表达式的右值中使用了 0.17。由于Go语言和C语言一样,编译器会尽量提高精确度,以避免计算中的精度损失。所以这里如果不指定变量 damageRate的类型,Go语言编译器会将 damageRate 类型推导为 float64,我们这里不需要 float64 的精度,所以需要强制指定类型为 float32。
  3. 第 7 行:将变量attack 和 defence 相减后的数值结果依然为整型,使用 float32() 将结果转换为 float32 类型,再与 float32 类型的 damageRate 相乘后,damage 类型也是 float32 类型。
  4. 第 8行:打印输出变量damage 的值。

注意:变量damage的右值是一个复杂的表达式,整个过程既有 attack 和 defence 的运算还有强制类型转换。强制类型转换会在后面的章节中介绍。

在Go语言中,还有一种更为精简的var 声明变量方式,例如:

hp := 100

这是Go语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。此处需要注意,由于使用了“:=”而不是赋值的“=”,因此推导声明写法的左值变量必须是没有定义过的变量。如果定义过,将会发生编译错误。如果 hp 已经被声明过,但依然使用“:=”时编译器会报错,代码如下:

//声明 hp 变量
var hp int
//再次声明并赋值
hp := 10

此时编译报错如下:

no new variables on left side of :=

上述报错信息的含义是,在“:=”的左边没有新变量出现,意思就是“:=”的左边变量已经被声明了。

在实际的开发应用中,短变量声明格式比较常见,比如下面的代码:

conn, err := net.Dial("tcp","127.0.0.1:8080")

在上述代码中,net.Dial 提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象(conn),一个是错误对象(err)。如果是标准格式将会变成:

var conn net.Conn
var err error
conn, err = net.Dial("tcp", "127.0.0.1:8080")

因此,短变量声明并初始化的格式在开发中使用比较普遍。

注意:在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名可能是重复声明的,编译器也不会报错,代码如下:

conn, err := net.Dial("tcp", "127.0.0.1:8080")
conn2, err := net.Dial("tcp", "127.0.0.1:8080")

上面的代码片段,编译器不会报重复定义错误。

实例2-3:计算圆的面积和周长(源码路径:Go-codes\2\area.go

实例文件area.go的具体实现代码如下所示。

package main
import "fmt"
func main() {
	//1:确定出n的取值
	const PI = 3.14
	//2:接收用户输入的半径
	fmt.Println("请输入半径:")
	var r float64
	fmt.Scan(&r)
	//3:计算圆的面积
	area := PI * r * r
	//4:i算圆的周长
	p := 2 * PI * r
	//5:输出结果
	fmt.Printf("面积是%.2f\n", area)
	fmt.Printf("周长是%.2f", p)
}

在上述代码中同时用到了变量和常量的声明和初始化操作,执行后先提示用户输入圆的半径,按下回车键后将打印输出对应的面积和周长:

请输入半径:
8
面积是200.96
周长是50.24

2.3.4  匿名变量

在Go语言中,匿名变量就是没有名字的变量;匿名变量不占用内存空间,不会分配内存,匿名变量与匿名变量之间也不会因为多次声明而无法使用。匿名变量的特点是一个下画线“_”,“_”本身就是一个特殊的标识符,可以像其他标识符那样用于变量的声明或赋值,但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。

实例2-4:分别打印输出语文和数学成绩(源码路径:Go-codes\2\ni.go

实例文件ni.go的具体实现代码如下所示。

package main
import "fmt"
func GetData() (int, int) {
	return 100, 88
}
func main(){
	a, _ := GetData()				//只需要获取第一个返回值,所以将第二个返回值的变量设为下画线(匿名变量)
	_, b := GetData()				//将第一个返回值的变量设为匿名变量。
	fmt.Println("你的语文和数学成绩分别为:",a,b)
}

在上述代码中,GetData()是一个函数,有关函数的详细知识将本书后面的内容中进行讲解。函数GetData() 是一个函数,拥有两个整型返回值,每次调用将会返回100和88这两个数值。执行后会输出:

你的语文和数学成绩分别为: 100 88

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值