「GO基础」变量


在这里插入图片描述
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
在这里插入图片描述

  • 推荐:「stormsha的主页」👈,持续学习,不断总结,共同进步,为了踏实,做好当下事儿~
  • 专栏导航
    • Python面试合集系列:Python面试题合集,剑指大厂
    • GO基础学习笔记系列:记录博主学习GO语言的笔记,该笔记专栏尽量写的试用所有入门GO语言的初学者
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 运维系列:总结好用的命令,高效开发
    • 算法与数据结构系列:总结数据结构和算法,不同类型针对性训练,提升编程思维

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

💖The Start💖点点关注,收藏不迷路💖

📒文章目录

  • 1、概述
  • 2、值类型和引用类型
  • 3、打印
  • 4、简洁形式,使用 := 赋值操作符
  • 5、init 函数
  • 6、练习


1、概述

在Go语言中,声明变量的一般形式是使用var关键字,但与许多编程语言不同的是,Go选择将变量的类型放在变量的名称之后,而不是之前。这种设计选择主要是为了避免类似于C语言中含糊不清的声明形式。

例如,在C语言中,如果你想要声明两个指针变量,你可能会写:int* a, b;。然而,在这个例子中,只有a是指针,而b不是。如果你想要两个变量都是指针,你需要将它们分开书写。

相比之下,在Go中,你可以轻松地将它们都声明为指针类型,如下所示:var a, b *int。这种语法更清晰,减少了潜在的错误和混淆。你可以在Go语言的声明语法页面上找到更多关于这个话题的讨论。

其次,这种语法能够按照从左至右的顺序阅读,使得代码更加容易理解。

var a int
var b bool
var str string

var (a intb boolstr string
)

在Go语言中,声明全局变量时通常使用因式分解关键字的写法。当一个变量被声明后,系统会自动为其赋予该类型的零值,例如int为0,float32(64)为0.0,boolfalsestring为空字符串,指针为nil。在Go中,所有内存都是经过初始化的。

变量的命名遵循骆驼命名法,即第一个单词小写,每个新单词的首字母大写,例如numShipsstartDate。但如果希望全局变量能被外部包使用,则需要将第一个单词的首字母也大写。

变量(包括常量、类型或函数)在程序中有一定的作用范围,称为作用域。如果一个变量在函数体外声明,则被认为是全局变量,可以在整个包甚至外部包(被导出后)使用,无论在哪个源文件中声明或调用。

在函数体内声明的变量称为局部变量,其作用域仅限于函数体内,参数和返回值变量也是局部变量。在if和for等控制结构中声明的变量的作用域仅限于相应的代码块内。通常情况下,局部变量的作用域可以通过代码块(用大括号括起来的部分)来判断。

虽然变量的标识符必须唯一,但可以在某个代码块的内层代码块中使用相同名称的变量,此时外部的同名变量会被暂时隐藏(结束内部代码块的执行后,隐藏的外部同名变量会重新出现,而内部同名变量会被释放),任何操作都只会影响内部代码块的局部变量。

变量可以在编译期间被赋值,赋值给变量使用运算符等号=,也可以在运行时对变量进行赋值操作。

a = 15
b = false

一般情况下,当变量a和变量b之间类型相同时,才能进行如 a = b 的赋值。

声明与赋值(初始化)语句也可以组合起来。

var identifier [type] = value
var a int = 15
var i = 5
var b bool = false
var str string = "Stormsha very NB!"

但是 Go 编译器的智商已经高到可以根据变量的值来自动推断其类型,这有点像 Ruby 和 Python 这类动态语言,只不过它们是在运行时进行推断,而 Go 是在编译时就已经完成推断过程。因此,你还可以使用下面的这些形式来声明及初始化变量:

var a = 15
var b = false
var str = "Stormsha very NB!"

var (a = 15b = falsestr = "Stormsha very NB!"numShips = 50city string
)

不过自动推断类型并不是任何时候都适用的,当你想要给变量的类型并不是自动推断出的某种类型时,你还是需要显式指定变量的类型,例如:

var n int64 = 2

然而,var a 这种语法是不正确的,因为编译器没有任何可以用于自动推断类型的依据。变量的类型也可以在运行时实现自动推断,例如:

var (GENDER = os.Getenv("GENDER")SOURCE = os.Getenv("SOURCE")GOROOT = os.Getenv("GOROOT")
)

这种写法主要用于声明包级别的全局变量,当你在函数体内声明局部变量时,应使用简短声明语法 :=,例如:

a := 1

下面这个例子展示了如何通过 runtime 包在运行时获取所在的操作系统类型,以及如何通过 os 包中的函数 os.Getenv() 来获取环境变量中的值,并保存到 string 类型的局部变量 path 中。

package mainimport ("fmt""runtime""os"
)func main() {var goos string = runtime.GOOSfmt.Printf("当前操作系统是: %s\n", goos)source := os.Getenv("SOURCE")fmt.Printf("资源位置是:%s\n", source)
}

如果你在 Windows 下运行这段代码,则会输出 The operating system is: windows 以及相应的环境变量的值;如果你在 Linux 下运行这段代码,则会输出 The operating system is: linux 以及相应的的环境变量的值。

2、值类型和引用类型

程序中所用到的内存在计算机中使用一堆箱子来表示(这也是人们在讲解它的时候的画法),这些箱子被称为“字”。根据不同的处理器以及操作系统类型,所有的字都具有 32 位(4 字节)或 64 位(8 字节)的相同长度;所有的字都使用相关的内存地址来进行表示(以十六进制数表示)。

所有像 intfloatboolstring 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值:

在这里插入图片描述

另外,像数组和结构 (struct)这些复合类型也是值类型。

当使用等号 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝:

在这里插入图片描述

可以通过&i来获取变量i的内存地址,例如:0xf840000040(每次的地址可能不同)。值类型的变量的值存储在栈中。内存地址会因机器而异,即使相同的程序在不同的机器上执行也会有不同的内存地址,因为每台机器可能有不同的存储器布局和位置分配。

更复杂的数据通常需要使用多个字,这些数据一般使用引用类型保存。引用类型的变量r1存储的是r1的值所在的内存地址(数字),或者内存地址中第一个字所在的位置。

在这里插入图片描述

内存地址被称为指针,它实际上存储在另一个字中。引用类型的指针可以指向连续内存地址中的多个字(连续内存布局),这是效率最高的存储形式;也可以将这些字分散存储在内存中,每个字都指示下一个字所在的内存地址。

当使用赋值语句r2 = r1时,只有引用(地址)被复制。如果r1的值被改变,则所有引用该值的指针都会指向修改后的内容,在这个例子中,r2也会受到影响。

在Go语言中,指针属于引用类型,其他引用类型还包括slicesmapschannel。被引用的变量存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。

3、打印

函数Printf可以在fmt包外部使用,因为它以大写字母P开头,主要用于向控制台打印输出。通常使用的格式为:

func Printf(format string, list of variables to be printed)

格式化字符串为:"当前操作系统是: %s\n"

这个格式化字符串可以包含一个或多个格式化标识符,例如:%..,其中..可以被不同类型的标识符替换,如%s表示字符串标识符,%v表示使用类型的默认输出格式的标识符。这些标识符对应的值从格式化字符串后的逗号开始按顺序添加,如果参数超过1个,也需要用逗号分隔。这些占位符可以很好地控制格式化输出的文本。

函数fmt.SprintfPrintf的作用完全相同,但它将格式化后的字符串作为返回值返回给调用者,因此可以在程序中使用包含变量的字符串。

函数fmt.Printfmt.Println会自动使用格式化标识符%v对字符串进行格式化,两者都会在每个参数之间自动添加空格,后者还会在字符串末尾添加换行符。例如:

fmt.Print("年龄:", 18)

将输出:"年龄:18"

4、简洁形式,使用 := 赋值操作符

在变量初始化时,我们可以省略变量类型,让系统自动推断。在概述中的声明语句中,都是使用var关键字声明的变量。因此,我们可以将它们简写为a := 50b := false

ab的类型(intbool)将由编译器自动推断。这是使用变量的首选形式,但只能在函数体内使用,不能用于全局变量的声明和赋值。使用操作符:=可以高效地创建一个新的变量,这被称为初始化声明。

在相同的代码块中,我们不能对相同名称的变量再次使用初始化声明,例如:a := 20 是不被允许的,编译器会提示错误 "no new variables on left side of :="。但是,a = 20 是可以的,因为这是给相同的变量赋予一个新的值。

如果你在定义变量a之前使用它,会得到编译错误 "undefined: a"

如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:

func main() {var a string = "NB"fmt.Println("stormsha ")
}

尝试编译这段代码将得到错误 a declared and not used

此外,单纯地给 a 赋值也是不够的,这个值必须被使用,所以使用 fmt.Printf("stormsha ", a) 会移除错误。

但是全局变量是允许声明但不使用。

其他的简短形式为:

同一类型的多个变量可以声明在同一行,如:

var a, b, c int

多变量可以在同一行进行赋值,如:

a, b, c = 5, 7, "abc"

上面这行假设了变量 a,b 和 c 都已经被声明,否则的话应该这样使用:

a, b, c := 5, 7, "abc"

右边的这些值以相同的顺序赋值给左边的变量,所以 a 的值是 5, b 的值是 7,c 的值是 “abc”。这被称为 并行 或 同时 赋值。如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a。

空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。

_实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。

并行赋值也被用于当一个函数返回多个返回值时,比如这里的 val 和错误 err 是通过调用 Func1 函数同时得到:

val, err = Func1(var1)

5、init 函数

除了在全局声明中初始化,变量也可以在init()函数中初始化。init()函数是一种特殊的函数,不能被显式调用,而是在每个包完成初始化后自动执行,且执行优先级高于main()函数。

每个源文件可以包含多个init()函数,同一源文件中的init()函数按照从上到下的顺序执行。如果一个包有多个源文件包含init()函数,官方鼓励但不保证按照文件名的顺序调用。初始化总是以单线程的方式按包的依赖关系顺序执行。

init()函数的一个可能用途是在程序开始执行之前对数据进行检查或修复,以确保程序状态的正确性。

// trans/init.go
package transimport "math"var Pi float64func init() {Pi = 4 * math.Atan(1) // init() function computes Pi
}

在它的 init() 函数中计算变量 Pi 的初始值。

如下示例中导入了包 trans(需要 init.go 目录为 ./trans/init.go )并且使用到了变量 Pi:

package mainimport ("fmt""./trans"
)var twoPi = 2 * trans.Pifunc main() {fmt.Printf("2*Pi = %g\n", twoPi) // 2*Pi = 6.283185307179586
}

init() 函数也经常被用在当一个程序开始之前调用后台执行的 goroutine,如下面这个例子当中的 backend()

func init() {// setup preparationsgo backend()
}

6、练习

推断以下程序的输出,然后编译并执行它们,验证和你的推断是否一致。

练习1

package mainvar a = "G"func main() {n()m()n()
}func n() { print(a) }func m() {a := "O"print(a)
}

练习2:

package mainvar a = "G"func main() {n()m()n()
}func n() {print(a)
}func m() {a = "O"print(a)
}

练习3:

package mainvar a stringfunc main() {a = "G"print(a)f1()
}func f1() {a := "O"print(a)f2()
}func f2() {print(a)
}

❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏、分享下吧,非常感谢!👍 👍 👍

🔥🔥🔥道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

💖The End💖点点关注,收藏不迷路💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui-键盘

文章目录 键盘键盘——记忆宫殿入门——通过键盘发送一个字符串——typewrite()常规——键名——typewrite()常规——按下键盘——keyDown()常规——释放键盘——keyUp()升级——热键组合——hotkey() 键盘 pyautogui也有一些函数向计算机发送虚拟按键,让你能够填充…

【介绍下WebStorm开发插件】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

深入了解PBKDF2:密码学中的关键推导函数

title: 深入了解PBKDF2:密码学中的关键推导函数 date: 2024/4/20 20:37:35 updated: 2024/4/20 20:37:35 tags: 密码学对称加密哈希函数KDFPBKDF2安全密钥派生 第一章:密码学基础 对称加密和哈希函数 对称加密:对称加密是一种加密技术&…

[阅读笔记15][Orca]Progressive Learning from Complex Explanation Traces of GPT-4

接下来是微软的Orca这篇论文,23年6月挂到了arxiv上。 目前利用大模型输出来训练小模型的研究都是在模仿,它们倾向于学习大模型的风格而不是它们的推理过程,这导致这些小模型的质量不高。Orca是一个有13B参数的小模型,它可以学习到…

Java中的四种引用类型

6.Java中的引用类型 1.强引用 一个对象A被局部变量、静态变量引用了就产生了强引用。因为局部变量、静态变量都是被GC Root对象关联上的,所以被引用的对象A,就在GC Root的引用链上了。只要这一层关系存在,对象A就不会被垃圾回收器回收。所以只…

计算机视觉——OpenCV Python位运算与图像掩码

概述 位运算与图像掩码的结合允许对图像的特定区域进行精确的操作。通过使用位运算(如AND、OR、XOR和NOT),可以基于掩码的选择性地修改图像数据。位运算与图像掩码结合使用的一些关键点和应用场景: 选择性修改: 通过位…

内网云盘如何内网穿透实现公网访问

云盘是一种专业的互联网存储工具,是互联网云技术的产物,它通过互联网为企业和个人提供信息的存储、读取、下载等服务,具有安全稳定、海量存储的特点。随着企业信息化发展,云盘系统需求不断扩大,相关系统软件被广泛应用…

通用大模型研究重点之五:llama family

LLAMA Family decoder-only类型 LLaMA(Large Language Model AI)在4月18日公布旗下最大模型LLAMA3,参数高达4000亿。目前meta已经开源了80亿和700亿版本模型,主要升级是多模态、长文本方面工作。 模型特点:采用标准的…

IoC 思想简单而深邃

一、序言 本文跟大家聊聊 IoC 这一简单而深邃的思想。 二、依赖倒置原则 软件工程理论中共有六大设计原则: 单一职责原则:不存在多于一个的因素导致类的状态发生变更,即一个类只负责一项单一的职责。里氏替换原则:基类出现的地…

VSCode搭建内核源码阅读开发环境

0. 参考链接 使用VSCode进行linux内核代码阅读和开发_vscode阅读linux内核-CSDN博客 1. 搭建Linux内核源码阅读环境 现状,Linux内核源码比较庞大文件非常多,其中又包含的众多的宏定义开关配置选项,这使得阅读内核源代码称为一件头疼的事。 …

常见的七种排序

目录 一、插入排序 1、直接插入排序 2、希尔排序(缩小增量排序) 二、选择排序 3、直接选择排序 4、堆排序 三、交换排序 5、冒泡排序 6、快速排序 四、归并排序 7、归并排序 五、总结 一、插入排序 1、直接插入排序 思路: i 用来…

文本溢出体验进阶:CSS 技巧实现单行/多行隐藏展示以及实际场景应用,确保内容可读性和布局整洁性

CSS文本溢出隐藏是一种常见的场景,它广泛应用于各种网页设计中,旨在确保内容的可读性和布局的整洁性,特别是在空间有限或需要适应不同屏幕尺寸的情况下。 一、文本溢出隐藏并显示省略号 1、单行文本溢出隐藏并显示省略号 对于单行文本&…

paho-mqtt 库揭秘

文章目录 **paho-mqtt 库揭秘**第一部分:背景介绍第二部分:paho-mqtt 是什么?第三部分:如何安装这个库?第四部分:库函数使用方法第五部分:场景应用第六部分:常见Bug及解决方案第七部…

Swift-25-普通函数、闭包函数与Lamda表达式编程

函数 语法定义 先来看下swift中函数的定义,函数用关键字func来指定,语法相对复杂一点,主要有下列4种基本情况,还有比较复杂的,会在后续详细讲解。 无参函数定义 有参函数定义 一个简单的函数和函数调用示例如下&…

分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测

分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测 目录 分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类…

A1322 电烙铁发热芯热电偶温度与电压数据

就是这种四根线比较细的发热芯: 两根红色线是发热丝,另外两根是热电偶线,透明线是正极,不能搞错了。 非常粗略的测了一下,根本没有考虑误差。拿万用表直接测量热电偶的输出电压;用可调电源手动调节电压&am…

suse15 系统分区信息损坏修复案例一则

关键词 suse linux、系统分区fdisk、分区类型testdisk、grub2、bios There are many things that can not be broken! 如果觉得本文对你有帮助,欢迎点赞、收藏、评论! 一、问题现象 业务反馈一台suse服务器,因错误执行了fdisk分区…

Linux 服务器硬件及RAID配置实战

服务器详解 服务器分类 可以分为:塔式服务器、机架服务器、刀片服务器、机柜服务器等。 其中以机架式居多 服务器架构 服务器品牌: 戴尔、AMD、英特尔、惠普、华为、华3(H3C)、联想、浪潮、长城 服务器规格: 规格…

【 C++ 】 讲解与实现 对数器接口

什么是对数器 说是叫对数器,但我觉得叫做核验器更好。 为什么?因为其作用是核验算法是否正确,所以我觉得叫核验器更好。 注意:本文实现的是生成只能int类型的对数器,其余类型不支持。 对数器的原理 对于一个核验器&am…

怎么用手机远程控制电脑 远程控制怎么用

怎么用手机远程控制电脑:远程控制怎么用 在这个科技日新月异的时代,远程控制电脑已经成为了很多人的需求。有时,我们可能在外出时突然需要访问家中的电脑,或者在工作中需要远程操控办公室的电脑。这时,如果能用手机远…