GO—变量

Go语言是静态类型语言,因此变量(variable)是有明确类型的,编译器也会检查变量类型的正确性。

我们从计算机系统的角度来讲,变量就是一段或者多段内存,用于存储数据

1.1 标准格式

复制代码
var 变量名 变量类型

1

变量声明以关键字var开头,变量类型后置,行尾无须分号

举个例子

复制代码
//声明了一个名为age的变量,类型为int
var age int

1

2

如果你学过C语言,就会体会到这样声明的好处,比如C语言这样声明:int* a, b ,那么只有a是指针,b不是,这样会使人迷惑,如果想要两个变量都为指针,需要这样定义:int *a,*b。

在go语言中,我们使用这样的声明方式:var a,b *int,就可以轻松的将a,b都声明为指针。

变量的命名规则遵循驼峰命名法,即首个单词小写,每个新单词的首字母大写,例如: startDate

1.2 基本类型

计算机中数据存储的最小单位为bit(位),0或者1

byte:计算机中数据的基本单元,1字节=8bit,数据在计算机中存储或者计算,至少为1个字节

  • bool
  • string
  • int(随系统,一般是占用4个字节)、int8(占一个字节)、int16(占两个字节)、int32(占4个字节)、int64(占8个字节)
  • uint(无符号整数)、uint8、uint16、uint32、uint64、uintptr
  • byte // uint8 的别名
  • rune // int32 的别名 代表一个 Unicode 码
  • float32、float64
  • complex64、complex128

有符号和无符号的区别:int8 范围 -128-127,uint8 范围:0-255

当一个变量被声明之后,系统自动赋予它该类型的零值:

int 为 0,float 为 0.0,bool 为 false,string 为空字符串,指针为 nil

所有的内存在 Go 中都是经过初始化的。

复制代码
func main() {
	var age int
	age = 23
	fmt.Println(age)
}

1.3 不指明变量类型

复制代码
//设置游戏中角色的初始等级为1
var level = 1;

1

2

像上面这种声明变量的方式,并没有指明类型,Go语言中,在编译时会自动推导类型

我们可以使用

复制代码
fmt.Printf("%T", level)

1

进行类型输出。

复制代码
func main() {
	//年龄为1 ,进行自动类型推断
	var age = 1
	fmt.Printf("%T", age)

}

1.4 批量格式

觉得每行都用 var 声明变量比较烦琐?Go语言提供了批量声明的方式

复制代码
func main() {
	// 批量类型声明
	var (
		age    int     //年龄
		name   string  // 姓名
		length float32 //长度
	)
	age = 19
	name = "lct"
	length = 19.12
	fmt.Printf("age=%d,name=%s,length=%f", age, name, length)
}

1.5

我们可以省略var关键字,这样写起来更加便捷

复制代码
//i是变量名 1 是值(或者表达式)
i := 1

1

2

上面讲过,如果不指明类型,直接赋值,Go会自动推导类型

使用简短格式有以下限制:

  1. 定义变量,同时显式初始化

  2. 不能提供数据类型

  3. 只能用在函数内部

    func main() {
    age := 10
    fmt.Printf("%T", age)
    }

简短变量声明被广泛用于大部分的局部变量的声明和初始化,var 形式的声明语句往往用于需要显式指定变量类型的地方

2. 初始化变量

复制代码
	//两种初始化方式
	var length float32 = 13.23
	age := 10

以下的代码会出错:

复制代码
package main

func main() {
	
	var level int = 1
    // 再次声明并赋值 会报错 no new variables on left side of := (左边的变量已经被声明了,不能重复声明)
	level := 1
}

但是有特例

比如:net.Dial 提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象(conn),一个是错误对象(err)

正常的写法:

复制代码
package main

import (
	"fmt"
	"net"
)
func main() {

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

短变量的写法:

复制代码
func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(conn)
}

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

3. 小demo

变量交换,比如a=100,b=200,交换之后 a=200,b=100

如果是你,你会怎么样进行实现呢?

第一种

复制代码
func main() {
	var a int = 100
	var b int = 200

	var temp int

	temp = a
	a = b
	b = temp

	fmt.Println("a=", a, "b=", b)
}

第二种

复制代码
func main() {
	var a int = 100
	var b int = 200

    //异或操作
	a = a ^ b
	b = a ^ b
	a = a ^ b
    
	fmt.Println("a=", a, "b=", b)
}

第三种

复制代码
func main() {
	var a int = 100
	var b int = 200

	a, b = b, a
	fmt.Println("a=", a, "b=", b)
}
  1. 匿名变量
    使用多重赋值时,如果不需要在左值中接受变量,可以使用匿名变量

比如上面的例子:

复制代码
	//conn, err := net.Dial("tcp", "127.0.0.1:8080")
	//如果不想接受error的值,可以用 _ 来代替
	conn, _ := net.Dial("tcp", "127.0.0.1:8080")

匿名变量以"_"下划线表示

匿名变量不占用命名空间,也不会分配内存。匿名变量可以重复声明使用

"_"本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。

5. 作用域

一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。

了解变量的作用域对我们学习Go语言来说是比较重要的,因为Go语言(静态语言)会在编译时检查每个变量是否使用过,一旦出现未使用的变量,就会报编译错误。

如果不能理解变量的作用域,就有可能会带来一些不明所以的编译错误。

根据变量定义位置的不同,可以分为以下三个类型:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

5.1 局部变量

在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量都属于局部变量。

局部变量不是一直存在的,它只在定义它的函数被调用后存在,函数调用结束后这个局部变量就会被销毁。

复制代码
package main
import (
    "fmt"
)
func main() {
    //声明局部变量 a 和 b 并赋值
    var a int = 3
    var b int = 4
    //声明局部变量 c 并计算 a 和 b 的和
    c := a + b
    fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

5.2 全局变量

在函数体外声明的变量称之为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用"import"关键字引入全局变量所在的源文件之后才能使用这个全局变量。

全局变量声明必须以 var 关键字开头,如果想要在外部包中使用全局变量的首字母必须大写。

复制代码
package main
import "fmt"
//声明全局变量
var c int
func main() {
    //声明局部变量
    var a, b int
    //初始化参数
    a = 3
    b = 4
    c = a + b
    fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑。

复制代码
var name string = "xiaoming"

func main() {
	name := "xiaohong"

	fmt.Println(name) //xiaohong

}

5.3 形式参数

在定义函数时函数名后面括号中的变量叫做形式参数(简称形参)。形式参数只在函数调用时才会生效,函数调用结束后就会被销毁,在函数未被调用时,函数的形参并不占用实际的存储单元,也没有实际值。

形式参数会作为函数的局部变量来使用。

复制代码
func main() {

	var a, b int
	a = 10
	b = 20
	fmt.Println("main 中的 a:", a, " b:", b)
	c := sum(a, b)
	fmt.Println("c:", c)
}

func sum(a, b int) int {
	fmt.Println("sum中的a:", a, " b:", b)
	return a + b
}

//main 中的 a: 10  b: 20
//sum中的a: 10  b: 20
//c: 30
相关推荐
研究司马懿1 小时前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大15 小时前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰20 小时前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘1 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤1 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto3 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto5 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室6 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题6 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo