04 go语言(golang) - 变量和赋值过程
变量
在Go语言中,变量的定义和初始化是编程的基础部分。Go提供了多种方式来声明和初始化变量,以适应不同的使用场景。
基本变量声明
-
使用
var关键字:
使用var关键字可以在函数内部或外部声明变量。如果在函数外部声明,该变量为全局变量。var str1 string = "变量1" var int1 int = 123 fmt.Println(str1, int1)如果已经明确了初始值,则可以省略类型信息,让编译器自动推断类型:
var str2 = "变量2" var int2 = 123 fmt.Println(str2, int2) -
短变量声明:
在函数内部,你可以使用更简洁的短变量声明(Short variable declarations)方式:=。这种方式同时进行了声明和初始化,并且类型由右侧表达式推断得出。func main() {str3 := "变量3"int3 := 123fmt.Println(str3, int3) }
多重赋值
Go支持多个变量同时赋值:
//var a, b, c = "1", 2, 3.55a, b, c := "1", 2, 3.55// 使用 reflect 包中的 .TypeOf 函数。返回变量的类型信息fmt.Println("a的类型为:", reflect.TypeOf(a))fmt.Println("b的类型为:", reflect.TypeOf(b))fmt.Println("c的类型为:", reflect.TypeOf(c))
// 为相同类型的变量在同一行上声明和赋值//var a, b, c int = "1", 2, 3 // 错误,不能将字符串赋值给整数变量。 Go 不支持在同一行中为不同类型变量分配类型。var a, b, c int = 1, 2, 3fmt.Println("a的类型为:", reflect.TypeOf(a))fmt.Println("b的类型为:", reflect.TypeOf(b))fmt.Println("c的类型为:", reflect.TypeOf(c))
块声明(block declaration)语法。这种方式允许在一个 var 语句中声明多个变量,并为它们赋初始值。
var (a = 1111b = "bbb"c bool)fmt.Println(a, b, c)
零值(Zero Values)
在Go中,如果你只是声明一个变量而没有给它赋初值,则会自动被赋予该类型的零值:
- 数字类型(整型、浮点型等)的零值是
0 - 布尔型的零值是
false - 字符串的零值是空字符串
"" - 指针、切片、映射、通道、函数以及接口的零值都是
nil
例如:
var a stringvar b intvar c float64var d boolfmt.Printf("a的值:【%v】\n", a)fmt.Printf("b的值:【%v】\n", b)fmt.Printf("c的值:【%v】\n", c)fmt.Printf("d的值:【%v】\n", d)/*输出结果为:a的值:【】b的值:【0】c的值:【0】d的值:【false】*/
作用域
在Go语言中,作用域(Scope)指的是一个变量或者函数名字在程序中可以被访问的区域。
-
全局作用域:
- 如果一个变量是在所有函数之外定义的,则它被认为是全局变量,可以在整个包内部任何位置使用。如果需要在其他包中使用这些全局变量或函数,则它们必须首字母大写。
test1.go
package mainimport "fmt"var name = "全局变量"func main() {// 在同一包下的不同文件中可以访问并且修改全局变量printGlobalVar()fmt.Println(name) }test2.go
package mainimport "fmt"func printGlobalVar() {fmt.Println(name)name = "修改后的全局变量" } -
包级别作用域:
- 在同一个包内部,当变量或者常数被定义在所有函数之外时(但不一定非得在文件最顶端),这些标识符将对整个包内部可见。这意味着同一包下不同文件中的代码也可以访问这些变量。
- 全局作用域的变量首字母小写,其实就相当于包级别作用域的变量
-
文件级别作用域:
- 这个概念在 Go 语言中并不存在。Go 语言中最小的作用域单位是包级别作用域。
-
局部作用域:
- 在函数内定义的变量只能在该函数内部访问,并且这种限制也适应于该函数内定义的其他嵌套块结构如if条件、循环等。
func printLocalVar() {var localVar = "局部变量"fmt.Println(localVar) } -
块级别作用域:
- Go 语言支持诸如 if、for、switch 等控制结构,并且每个结构都会引入新的块范围。例如,在 if 语句中声明并初始化一个新变量,在该 if 块及其子块中该变量是可见和可访问的,但超出此范围后就不再可见。
func printBlockVar() {var localVar = "局部变量"// 代码块{var blockVar = "块级变量"fmt.Println(blockVar)fmt.Println(localVar) // 可以访问局部变量}//fmt.Println(blockVar) // 报错,无法访问块级变量 }
赋值过程
赋值过程及内存相关的知识,通过以下代码做分析
name := "这是一段字符串"nickname := name
- 声明并初始化
name:name被声明为一个新的局部变量,并且类型被推断为字符串(string)。它指向一个内存位置,该位置存储着字符串"这是一段字符串"。
- 声明并初始化
nickname:- 接下来,另一个新变量
nickname被声明,并使用短变量声明方式同时进行初始化。 - 在这个赋值操作中,由于字符串在Go中是不可变的,并且赋值操作只是复制了引用(而非数据本身),因此
nickname也会指向同一块内存地址,即指向"这是一段字符串"的那块内存。 - 注意!
name和nickname都指向同一个字符串字面值"这是一段字符串"的实际数据。这意味着他们共享相同的底层字节数组。然而,每个字符串变量(如name和nickname)本身也是一个独立的实体,拥有自己的内存地址。
- 接下来,另一个新变量
- 内存共享:
- 重要的是理解,在这种情况下,没有新的字符串数据被创建。两个变量
name和nickname实际上共享相同的底层数据。这意味着对于只读数据如字符串来说非常高效。
- 重要的是理解,在这种情况下,没有新的字符串数据被创建。两个变量
- 垃圾回收考虑:
- 在Go语言中,当没有任何引用指向某块内存时(即不再有任何方式访问该内存),这块内存就可能被标记为可回收。只要任何一个变量仍然引用着那块内存(即使其中一个已经超出了作用域),那么该内存就不会被垃圾回收器回收。只有当所有引用(name和nickname)都消失时才会释放相关资源。
结合代码说明
package mainimport ("fmt""unsafe" // 代码使用 `unsafe` 包将变量的地址转换为 `stringHeader` 类型的指针,以便访问字符串的底层数据指针。
)func main() {// 情况1 变量地址不同,指向的值地址相同name := "这是一段字符串"nickname := namefmt.Println("============打印变量的地址信息============")fmt.Printf("变量'name' 地址:【%p】\n", &name)fmt.Printf("变量'nickname' 地址:【%p】\n", &nickname)// 使用unsafe包来获取字符串底层数据指针nameDataPointer1 := (*stringHeader)(unsafe.Pointer(&name)).DatanicknameDataPointer1 := (*stringHeader)(unsafe.Pointer(&nickname)).Datafmt.Printf("'name'数据的指向地址: %x\n", nameDataPointer1)fmt.Printf("'nickname'数据的指向地址: %x\n\n", nicknameDataPointer1)// 情况2 变量地址不同,指向的值地址也相同,因为字符串是不可变的nickname = "这是一段字符串"fmt.Println("============打印变量的地址信息============")fmt.Printf("变量'name' 地址:【%p】\n", &name)fmt.Printf("变量'nickname' 地址:【%p】\n", &nickname)// 使用unsafe包来获取字符串底层数据指针nameDataPointer2 := (*stringHeader)(unsafe.Pointer(&name)).DatanicknameDataPointer2 := (*stringHeader)(unsafe.Pointer(&nickname)).Datafmt.Printf("'name'数据的指向地址: %x\n", nameDataPointer2)fmt.Printf("'nickname'数据的指向地址: %x\n\n", nicknameDataPointer2)// 情况3 变量地址不同,指向的值地址不同nickname = "这是一段字符串!"fmt.Println("============打印变量的地址信息============")fmt.Printf("变量'name' 地址:【%p】\n", &name)fmt.Printf("变量'nickname' 地址:【%p】\n", &nickname)// 使用unsafe包来获取字符串底层数据指针nameDataPointer3 := (*stringHeader)(unsafe.Pointer(&name)).DatanicknameDataPointer3 := (*stringHeader)(unsafe.Pointer(&nickname)).Datafmt.Printf("'name'数据的指向地址: %x\n", nameDataPointer3)fmt.Printf("'nickname'数据的指向地址: %x\n\n", nicknameDataPointer3)}/*
stringHeader用于获取字符串的底层数据指针,这个结构体是 Go 语言中字符串的内部表示。
`Data` 是一个 `uintptr` 类型的字段,它用来存储指向字符串数据的指针
`Len` 存储字符串的长度。
*/
type stringHeader struct {Data uintptr // 指向实际数据的指针Len int // 字符串的长度
}
打印结果
============打印变量的地址信息============
变量'name' 地址:【0xc000014070】
变量'nickname' 地址:【0xc000014080】
'name'数据的指向地址: 2f2a8fd
'nickname'数据的指向地址: 2f2a8fd============打印变量的地址信息============
变量'name' 地址:【0xc000014070】
变量'nickname' 地址:【0xc000014080】
'name'数据的指向地址: 2f2a8fd
'nickname'数据的指向地址: 2f2a8fd============打印变量的地址信息============
变量'name' 地址:【0xc000014070】
变量'nickname' 地址:【0xc000014080】
'name'数据的指向地址: 2f2a8fd
'nickname'数据的指向地址: 2f2b3eb
这段 Go 语言代码演示了字符串在不同情况下的内存地址和底层数据指针的变化。代码分为三个部分,每部分都打印了变量的内存地址和它们指向的字符串数据的地址。这里使用了 unsafe 包来操作指针和内存,这是 Go 语言中一个特殊的包,允许程序绕过类型安全性的限制。
-
情况1:创建了两个变量
name和nickname,它们被赋予了同一个字符串字面量。由于字符串是不可变的,nickname实际上是对name所指向的字符串的一个别名。因此,尽管name和nickname作为变量有不同的内存地址,它们指向的字符串数据的地址是相同的。 -
情况2:
nickname被重新赋值为与name相同的字符串字面量。由于字符串是不可变的,这个新的字符串字面量可能会指向与name相同的内存地址,或者可能会创建一个新的字符串实例,这取决于 Go 运行时的优化。在这个例子中,由于字符串内容相同,nickname可能指向了与name相同的内存地址。 -
情况3:
nickname被重新赋值为一个不同的字符串字面量,这次字符串内容与name不同。由于字符串是不可变的,这个新的字符串字面量将创建一个新的内存地址来存储这个新的字符串内容。因此,nickname将指向一个新的内存地址,与name所指向的地址不同。
待后面我们展开学习go中的 *(指针)与&(地址)后,再回头来理解上面的赋值和内存相关,会容易理解很多。
相关文章:
04 go语言(golang) - 变量和赋值过程
变量 在Go语言中,变量的定义和初始化是编程的基础部分。Go提供了多种方式来声明和初始化变量,以适应不同的使用场景。 基本变量声明 使用var关键字: 使用var关键字可以在函数内部或外部声明变量。如果在函数外部声明,该变量为全…...
语言/图像/视频模型一网打尽!BigModel大模型开放平台助力开发者轻松打造AI新应用!
2024年8⽉28⽇,在ACM SIGKDD(国际数据挖掘与知识发现⼤会,KDD)上会议现场,智谱AI重磅推出了新⼀代全⾃研基座⼤模型 GLM-4-Plus、图像/视频理解模型 GLM-4V-Plus 和⽂⽣图模型 CogView3-Plus。这些新模型,已…...
Go语言Linux环境搭建以编写第一个Go程序
目录 文章目录 目录Go语言入门1、说明2、CentOS7安装Go3、编写第一个程序3.1、编写程序3.2、运行程序3.3、生成二进制文件4、编写第一个web程序4.1、编写代码4.2、运行程序4.3、测试访问4.4、生成二进制配置Vim-go语法高亮1)、下载和设置Vundle.vim(vim安装插件的工具)2)、…...
使用 Go 构建一个最小的 API 应用
最近有项目要使用 Go 开发,作为一个. NET Core 选手,准备先撸一个包含 CRUD 的最小 MVP 项目练手。 要创建一个 TODO 应用,会创建下面这些接口: APIDescriptionRequest bodyResponse bodyGET /todoitemsGet all to-do itemsNone…...
MySQL 日常维护指南:常见任务、频率及问题解决
MySQL 作为一种广泛使用的开源关系型数据库,随着数据量和应用复杂性的增加,定期的数据库维护对于保持系统高效运行至关重要。通过合理的日常维护,数据库管理员能够确保 MySQL 数据库的稳定性、性能以及数据的完整性。本文将介绍 MySQL 的常见…...
oracle ORA-24920:列大小对于客户机过大
问题描述 在一次读取某个视图数据过程中,当数据读取到x条时,报错ORA-24920:列大小对于客户机过大。 通过查询资料得知,oracle 数据库升级到了12c,VARCHAR2的容量也从4000升级到了32767。 所以猜测某个字段的长度超过4…...
使用 Docker compose 部署 Nacos(达梦数据库)
1. 制作镜像的源码地址 https://github.com/wangsilingwsl/nacos-dm.git 参考的开源项目:https://github.com/jeecgboot/JeecgBoot/tree/master/jeecg-boot/jeecg-server-cloud/jeecg-cloud-nacos (master分支;tag:v3.7.1&#…...
人工智能 | 阿里通义千问大模型
简介 通义千问系列模型为阿里云研发的大语言模型。千问模型基于 Transformer 架构,在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍、代码等。同时,在预训练模型的基础之上&…...
Windows环境下Qt Creator调试模式下qDebug输出中文乱码问题
尝试修改系统的区域设置的方法: 可以修复问题。但会出现其它问题: 比如某些软件打不开,或者一些软件界面的中文显示乱码! 暂时没有找到其它更好的办法。...
java防止表单重复提交的注解@RepeatSubmit
代码解释 RepeatSubmit 是一个自定义注解,通常用于防止表单重复提交。这个注解可以应用于控制器方法上,以确保同一个请求在一定时间内不会被多次提交。以下是一些常见的参数和用法: value: 注解的名称或描述。 interval: 两次请求之间的最小间…...
HTTP快速入门
HTTP报文结构 HTTP 协议主要由三大部分组成: ● 起始行(start line):描述请求或响应的基本信息; ● 头部字段(header):使用 key-value 形式更详细地说明报文; ● 消息正…...
Nacos简介
Nacos是一个开源的动态服务发现、配置管理和服务管理平台,由阿里巴巴集团开发并开源。它提供了服务注册与发现、配置管理、动态DNS服务、服务健康监测、权重和流量管理等核心特性,非常适合构建云原生应用和微服务架构。 Nacos的核心功能包括:…...
基于深度学习的稳健的模型推理与不确定性建模
基于深度学习的稳健模型推理与不确定性建模,是现代AI系统中至关重要的研究方向。随着深度学习在各类应用中的成功,如何保证模型在面对未知或不确定性输入时仍能做出稳健的推理,并能够量化这种不确定性,成为关键问题。稳健性与不确…...
C语言 sizeof 的介绍,以及sizeof计算数组名、 数组首地址、数组的元素之间的区别
一、sizeof 介绍 sizeof 是 C 语言中的一个运算符,用于计算数据类型或变量在内存中占用的字节数。用于计算数据类型或变量所占的内存大小,以字节为单位。它可以在编译时计算其操作数的大小,并返回一个 size_t 类型的值。它可以帮助了解不同类…...
深入理解Oracle闪回技术
引言: Oracle 闪回(Flashback)是一组强大的功能,用于恢复数据库中的数据或对象到过去的某个时间点或状态,而无需进行传统的基于备份和恢复的操作。 Oracle 闪回的主要类型 1. 闪回查询(Flashback Query&…...
Go 语言初探
Google 公司有一个传统,允许员工利用 20% 的工作时间开发自己的实验项目。2007 年 9月,UTF-8 的设计者之一 Rob Pike(罗布.皮克)在 Google 的分布式编译平台上进行 C++ 编译时,与同事 Robert Griesemer (罗布.格里泽默)在漫长的等待中讨论了编程语言面临的主要问题。他们一…...
使用ROS资源编排一键部署LNMP建站环境,手动整理教程
LNMP是目前主流的网站服务器架构之一,适合运行大型和高并发的网站应用,例如电子商务网站、社交网络、内容管理系统等。LNMP分别代表Linux、Nginx、MySQL和PHP。本文阿里云服务器网aliyunfuwuqi.com介绍如何使用阿里云资源编排服务(ROS&#x…...
猎板PCB镍钯金工艺你了解多少?
PCB镍钯金工艺,也称为ENEPIG(Electroless Nickel Electroless PALLADIum Gold)工艺,是一种在PCB表面处理中使用的先进工艺。这种工艺通过在PCB线路板上形成一层镍钯合金层,有效地提高了线路板的耐氧化性、耐腐蚀性和可…...
热更新解决方案2 —— Lua语法相关知识点
概述 开发环境搭建 Lua语法 1.第一个Lua程序 2.变量 print("******变量*******"); --lua当中的简单变量类型 -- nil number string boolean -- lua 中所有的变量声明 都不需要声明变量类型 它会自动的判断类型 -- 类似C# 中的var --lua中的一个变量 可以随便赋值 ——…...
【c++ arx选项板】
static void xlArx_gmenu(void) {if (!g_pPaletteSetEx){g_pPaletteSetEx=CTunnelSectionPaletteSetEx::Instance(...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
