Go语言--变量、常量

一、变量

1.1 声明变量

1、标准格式
var 变量名 变量类型
Q:为什么Go语言把数据类型放在后面?
答:Go语言这是一种自左向右的声明风格,这种声明的风格的好处是,变量名和类型是完全分隔的。当类型变得复杂时,它的价值就体现出来了。
特别类型是函数指针的时候,C语言的声明语法容易让人弄混淆,而Go语言的这种自左向右的声明语法,即使在冗长的声明中也能很清晰地知道整个声明结构。
x int         //声明变量
p *int        //声明指针
a [3]int      //声明数组
func f(a int, b int) int  //声明函数,函数名为f

 <说明> Go语言的变量声明是以var关键字开头,后置变量类型,行尾无须分号。

2、批量格式

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

 批量格式使用var和小括号(),可以将一组变量定义在一起。

指针

    在Go语言中,数组(array)和切片(slice)在声明时,类型语法把方括号放在了类型的左边,但是在表达式语法中却又把方括号放在了右边。
var a []int   //声明int型切片
x = a[1]      //将切片元素赋值给变量x

//类似的,Go语言的指针沿用了C的星号(*)的记法,声明的时候星号是在变量名的右边,但在表达式语法中却又把星号放在变量的左边:
var p *int    //声明int型指针p
x = *p        //将指针p所指向的内存单元的值赋值给变量x

可以看到,Go语言的指针的声明与C语言是不一样的,但是对指针的运算使用的语法是相同的。

1.2 初始化变量

Go语言在声明变量时,会自动对变量对应的内存区域进行初始化操作。每个变量都被初始化其类型的默认值。例如:

  • 整型和浮点型变量的默认值是0。
  • 字符串变量的默认值为空字符串。
  • 布尔型变量的默认值是false。
  • 切片、函数、指针变量、接口变量的默认值是nil。
当然,你也可以在声明变量的同时赋予变量一个初始值。
<回顾> 在C/C++语言中,在声明变量时,并不会对变量对应内存区域进行清理操作。此时,变量值可能是完全不可预期的结果。开发者需要习惯在声明变量的同时进行初始化操作,稍有不慎,就会造成不可预知的后果。
1、标准格式
var 变量名 类型 = 表达式
示例如下:
var hp int = 100

2、编译器推导类型的格式

在上面标准的基础上,将类型int省略,编译器会根据等号右边的表达式推导出等号右边的hp变量的类型。因此,上面的语句简写成下面的语句:

var hp = 100

等号右边的部分在编译原理中被称作“右值”。

下面的一个例子:

var attack 40
var defence 20
var damageRate float32 = 0.17
var damage = float32(attack-defence) * damageRate

Go语言和C语言一样,编译器会尽量提供精确度,以避免计算中精度损失。默认情况下,如果不指定damageRate变量的类型,Go语言编译器会将damageRate类型推导为float64。本例中,指定了其类型为float32,所以不需要float64的精度。

float(attack-defence)将两个整型变量相减后的结果强制转换为float32类型,然后再与float32类型的damageRate相乘,因此damage类型也是float32类型。

<建议> 在实际的开发过程中,不太建议使用这种简写的变量初始化方式,最好还是带上类型,即使用标准格式来初始化变量。

3、短变量声明并初始化

var的变量声明还有一种更为精简的写法,例如:

hp := 100

这是Go语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。

<注意> 由于使用了":=",而不是赋值符号"=",因此推导声明的左值变量必须是一个没有定义过的变量。若已经定义过,将会发生编译报错。例如:

var hp int
hp := 100

编译时会报错:no new variables on left side of :=

提示,在:=左边没有新变量出现,意思就是“:=” 的左边变量已经被声明过了。短变量的声明方式在开发中的例子较多,例如:

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

 如果是标准声明格式,将会变成:

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")

上面的代码片段中,编译器不会报err重复定义的错误,因为 conn2 是新声明的变量。

1.3 多个变量同时赋值(多重赋值)

使用Go语言的“多重赋值”特性,可以轻松完成两个变量的交换。

var a int = 100
var b int = 200
b, a = a, b
  • 多重赋值时,变量的左值和右值按从左到右的顺序赋值。即先是=号右边的a先赋值给左边的b,然后是=号右边的b赋值给=号左边的a。
  • 多重赋值在Go语言的错误处理和函数返回值中会大量地使用。

例如,使用Go语言进行排序时就需要使用多重交换。

type IntSlice []int  //将[]int声明为IntSlice类型,即类型别名
func (p IntSlice) Len() int { return len(p) }  //切片长度函数
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }  //根据索引比较元素的大小并返回结果
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }  //根据索引交换两个元素的值

1.4 匿名变量

在使用多重赋值时,如果不需要在左值中接收变量值,可以使用匿名变量。Go语言中匿名遍历是一个下划线"_"。使用匿名变量时,只需要在变量声明的地方使用下划线替换即可。

例如:

func GetData() (int, int) {
    return 100, 200
}
a, _ := GetData()
_, b := GetData()

匿名变量的特点:匿名变量不占用内存空间,不会进行内存分配。匿名变量与匿名变量之间也不会因为多次声明而无法使用。可以将匿名变量理解为一种占位符。

二、常量

常量是恒定不变的量,例如圆周率。可以在编译器对常量表达式进行计算求值,并在运行期使用该计算结果,但是计算结果无法被修改。

常量的声明使用关键字const。例如:

const PI = 3.1415926
const e  = 2.718281

多个常量也可一起声明,使用const关键字+小括号。例如:

const (
    PI = 3.1415926
    e  = 2.718281
)

因为常量的值是在编译阶段就确定了,所以可以用于数组声明。例如:

const sise = 4
var arr [size]int

2.1 枚举常量 —— 一组常量值

 Go语言目前还没有枚举类型(目前最新版是Go1.15),但是可以使用常量配合itoa模拟枚举常量。示例:

type Weapon int  //声明一个类型别名
const (
    Arrow Weapon = itoa  //开始生成枚举值,默认值为0
    Shuriken
    SniperRifle
    Rifle
    Blower
)
//输出所有枚举值
fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)

//使用枚举类型并赋值
var weapon Weapon = Blower
fmt.Println(weapon)

代码输出结果如下:

0 1 2 3 4

4

代码说明

  • 将int类型定义为Weapon类型,这只是为int类型设置了一个类型别名(Type Alias)。就像枚举类型其实本质是整型一样。当然,某些情况下,如果需要int32和int64的枚举,也是可以的。
  • 将Arrow常量的类型标识为Weapon类型后,const下方的常量可以是默认类型的,默认时,默认使用前面指定的类型作为常量类型。因此Arrow后面的常量默认也都是Weapon类型了。使用itoa可以进行常量值的自动生成。itoa的起始值是0,一般情况下也是建议枚举值从0开始。一个const声明内的每一行常量声明,将会自动套用前面的itoa格式,并自动增加,默认增加1。
  • 当然,itoa不仅仅只生成每次增加1的枚举常量。还可以利用itoa来做一些强大的枚举常量值生成器。例如,下面的代码可以方便生成标志位常量:
const (
    FlagNone = 1 << itoa
    FlagRed
    FlagGreen
    FlagBlue
)
fmt.Printf("%d %d %d\n", FlagRed, FlagGreen, FlagBlue)
fmt.Printf("%b %b %b", FlagRed, FlagGreen, FlagBlue)    //以二进制格式输出
输出结果:
2 4 8
10 100 1000
代码说明》本例子中,itoa使用了移位操作,每次将上一次的值左移一位,以做出每一位的常量值。以二进制格式输出,可以清晰地看到每一位的变化。
示例程序:将枚举值转换为字符串。
/*
程序描述:将枚举值转换成字符串。
说明: Go语言没有枚举类型,可以使用常量配合iota模拟枚举。
*/

package main

import "fmt"

//将ChipType定义为int类型
type ChipType int
const (
    None ChipType = iota //iota从0开始计数
    CPU
    GPU
)

//定义ChipType类型的方法String(),返回字符串
func (c ChipType) String() string {
    switch c {
        case None:
            return "None"
        case CPU:
            return "CPU"
        case GPU:
            return "GPU"
    }
    return "N/A"
}

func main() {
    //输出CPU的值并以整数格式显示
    fmt.Printf("%s %d\n", CPU, CPU)
}

输出结果:CPU 1

《代码说明》这里我们实现了ChipType类型的String()方法,当这个类型需要显示为字符串时,Go语言会自动寻找String()方法并进行调用。输出格式%s对应的是字符串类型,%d对应的是整型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值