Go var

2020-12-28  本文已影响0人  JunChow520

Go语言基础语法,Go在很多特性上和C非常相近。

标识符

编程语言中标识符实际上是程序员定义的具有特殊意义的名称,比如变量名、常量名、函数名等。

关键字

Golang中拥有25个关键字和37个保留字。

变量

程序运行过程中数据都是保存在内存中的,若要在代码中操作某个数据就需要去内存上寻找对应变量。若直接在代码中通过内存地址去操作变量,代码的可读性会非常差且容易出错。利用变量可将数据的内存地址保存起来,日后可直接使用变量即可找到内存上与之对应的数据了。

变量声明

变量在数学概念中表示没有固定值且可改变的数,在计算机系统实现中变量则是一段或多段用来存储数据的内存。

Go是静态类型语言,因此变量需要明确类型,因为编译器会检查变量类型的正确性。

变量声明方式

标准声明方式

使用var name type声明变量时以关键字var开头,后置变量类型,行尾无需分号。

var name type
//C语言声明变量指针
int* a, b;
//Go语言声明变量指针
var a,b *int

短变量声明

func main() {
  x := 0
}

简短形式可声明和初始化一组变量

i,j := 0,1

批量声明

使用var关键字和小括号()可以将一组变量定义放在一起,用于批量声明。

var (
  id int
  name string
  score []float32
  job struct {
    post string
  }
  lock func() bool
)

变量初始化

变量初始化标准格式

var 变量名 数据类型 = 表达式

比如:游戏玩家初始血量为100

var hp int = 100

Go在声明变量时会自动对变量相应的内存空间进行初始化操作,初始化为对应数据类型的默认值。

数据类型 默认值
整型变量 0
浮点型变量 0.0
字符串变量 空字符串
布尔型变量 false
指针、函数、切片变量 nil

编译器类型推导

在变量初始化标准格式的基础上,编译器会尝试根据等号右边的表达式(编译原理中称之为右值rvalue)推导变量的数据类型。

package main

import (
    "fmt"
)

func main() {
    var hp = 100
    var defence = 20
    var damageRate float32 = 0.15
    var damage = float32(hp-defence) * damageRate
    fmt.Println(hp, defence, damageRate, damage)
}

Go中编译器为了尽量提高精确度以避免计算中的精度损失,默认会将浮点数转换为float64,可强制指定浮点数的类型为float32

使用简短方式声明变量,实质上正是推导声明的写法,编译器会自动根据右值推导出左值的数据类型。如果变量已经被声明过再次使用:=类型推导声明则会报错,因为推导声明写法中左值必须是没有定义过的变量。若已经定义过则会发生编译错误。

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

不过需要注意的是在多个变量声明和赋值中,只要至少有一个新变量的声明出现在左值中,那么即使其它变量名可能出现重复,编译器是不会报错的。

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

匿名变量

匿名变量即没有名称的变量,编码中使用没有名称的变量、类型或方法可以增强代码的灵活性。在Lua等变成语言中,匿名变量又称为哑元变量。

func test() (int, int){
    return 1, 2
}
func main() {
    x, _ := test()
    _, y := test()
    fmt.Println(x, y)//1 2
}

多重赋值

编码中变量交换往往需要中间变量进行临时保存,早期计算机内存资源精贵,变量交换非常奢侈。到了Go语言时内存不再是稀缺资源,为了精简写法,可使用Go提供的多重赋值完成变量交换的任务。

变量交换算法

var x int = 100
var y int = 200
var z int

z = x
x = y
y = z
fmt.Println(x, y, z)//200 100 100

避免使用中间变量

var x int = 100
var y int = 200

x = x ^ y
y = y ^ x
x = x ^ y
fmt.Println(x, y)//200 100

Go多重赋值实现变量交换

var x int = 100
var y int = 200
x,y = y,x
fmt.Println(x, y)//200 100

多重赋值时变量的左值和右值按从左到右的顺序赋值

多重赋值在错误处理和函数返回值中会大量使用,比如排序时使用多重赋值。

// 声明[]int类型的整型切片类型
type IntSlice []int
//为整型切片类型的数据提供切片长度方法
func (data IntSlice) Len() int { return len(data) }
//获取整型切片中较小元素
func (data IntSlice) Less(i, j int) bool { return data[i] < data[j] }
//交换整型切片数组中元素的值
func (data IntSlice) Swap(i, j int) { data[i], data[j] = data[j], data[j]}

变量作用域

变量的作用域即变量(常量、类型、函数)在程序中的作用范围,Go语言在编译时会检查每个变量是否使用过,一旦出现未使用过的变量则会报出编译错误。

根据变量定义的位置,可将变量分为三类,每类变量的作用域互不相同。

局部变量

var x int = 1
var y int = 2
result := x + y
fmt.Printf("x = %d, y = %d, result = %d\n", x, y, result)

全局变量

//声明全局变量
var pi float32 = 3.14
func main(){
    //声明局部变量
    var pi int = 100
    fmt.Println(pi)//100
}

形式参数

func sum(x, y int) int{
    result := x + y
    return result
}

func main(){
    var x int = 1
    var y int = 2
    z := sum(x, y)
    fmt.Printf("x = %d, y = %d, z = %d", x, y, z)
}

变量逃逸

堆(heap)

栈(stack)

程序编译阶段,编译器会根据实际情况自动选择在堆或栈上分配局部变量的存储空间,不论是使用var还是new关键字声明的变量都不会影响编译器的选择。

变量的逃逸行为发生时,逃逸的变量需要额外的分配内存,对性能优化可能会产生细微的影响。

生命周期

变量的生命周期是指程序运行期间变量有效存在的时间间隔

虽然Go能够帮助完成内存的分配和释放,但为了开发出高性能的应用,仍需要了解变量的声明周期。若将局部变量赋值给全局变量将会阻止垃圾回收器对局部变量的收回,导致不必要的内存占用,从而影响程序的性能。

变量的生命周期与变量的作用域有着密不分割的关系

变量类型

Go语言中常见的基础数据类型包括:

数据类型 描述 初始值
bool 布尔值 false
string 字符串 空字符串""
int/int8/int16/int32/int64/ 整型 0
uint/uint8/uint16/uint32/uint64 无符号整型 0
byte uint8别名 0
rune int32别名表示Unicode码 0
float32/float64 浮点数 0.0
complex64/complex128 复数 0.0
上一篇 下一篇

猜你喜欢

热点阅读