「GO基础」变量

news2024/10/5 16:19:49

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

  • 推荐:「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 int
	b bool
	str 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 = 15
	b = false
	str = "Stormsha very NB!"
	numShips = 50
	city 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 main

import (
	"fmt"
   "runtime"
	"os"
)

func main() {
	var goos string = runtime.GOOS
	fmt.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 trans

import "math"

var Pi float64

func init() {
   Pi = 4 * math.Atan(1) // init() function computes Pi
}

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

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

package main

import (
   "fmt"
   "./trans"
)

var twoPi = 2 * trans.Pi

func main() {
   fmt.Printf("2*Pi = %g\n", twoPi) // 2*Pi = 6.283185307179586
}

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

func init() {
   // setup preparations
   go backend()
}

6、练习

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

练习1

package main

var a = "G"

func main() {
   n()
   m()
   n()
}

func n() { print(a) }

func m() {
   a := "O"
   print(a)
}

练习2:

package main

var a = "G"

func main() {
   n()
   m()
   n()
}

func n() {
   print(a)
}

func m() {
   a = "O"
   print(a)
}

练习3:

package main

var a string

func main() {
   a = "G"
   print(a)
   f1()
}

func f1() {
   a := "O"
   print(a)
   f2()
}

func f2() {
   print(a)
}

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

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

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

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

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

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

相关文章

上位机图像处理和嵌入式模块部署(树莓派4b和视觉slam十四讲)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 实际使用中,树莓派4b是非常好的一个基础平台。本身板子价格也不是很贵,建议大家多多使用。之前关于vslam,也就是…

《强势》如何在工作、恋爱和人际交往中快速取得主导权? - 三余书屋 3ysw.net

强势:如何在工作、恋爱和人际交往中快速取得主导权? 大家好,今天我们要解读的是一本名为《强势》的书籍。我将花费大约20分钟的时间,为您详细讲解这本书的精华内容,包括如何在家庭关系、职场关系和朋友关系中迅速取得…

Python可视化数据分析-柱状图/折线图

一、前言 使用python编写一个图表生成器,输入各公司的不良品数量,可以在一张图中同时展示数据的柱状图和折线图。 效果如下: 二、基础知识 绘制折线图和柱状图主要使用到了 pyecharts.charts 模块中的 Line 和 Bar 类。它们允许用户通过简…

Java关键字和API

1 this和super关键字 1.this和super的意义 this:当前对象 在构造器和非静态代码块中,表示正在new的对象 在实例方法中,表示调用当前方法的对象 super:引用父类声明的成员 无论是this和super都是和对象有关的。 2.this和sup…

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

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

嵌入式物联网实战开发笔记-乐鑫ESP32芯片功能对比以及功能选型【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载: 链接:https://pan.baidu.com/s/1ATvRnAZvxkev-PJfd3EAPg?pwd4e33 提取码:4e33 2.1 初识 ESP32 ESP32-S3 是一款低功耗的 MCU 系统级芯片 (SoC),支持 2.4 GHz Wi-Fi 和低功耗蓝牙 (…

【PythonCode】力扣Leetcode16~20题Python版

【PythonCode】力扣Leetcode16~20题Python版 前言 力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台,很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。 在Leetcode上刷题,可以选择各种主流的编程语言,如C…

汇编语言(详解)

汇编语言安装指南 第一步:在github上下载汇编语言的安装包 网址:GitHub - HaiPenglai/bilibili_assembly: B站-汇编语言-pdf、代码、环境等资料B站-汇编语言-pdf、代码、环境等资料. Contribute to HaiPenglai/bilibili_assembly development by creat…

一文让你彻底掌握操作符(超详细教程)

✅作者简介:大家好,我是小杨 📃个人主页:「小杨」的csdn博客 🔥系列专栏:小杨带你玩转C语言【初阶】 🐳希望大家多多支持🥰一起进步呀! 大家好呀!我是小杨。小…

学习笔记-数据结构-线性表(2024-04-18)- 单向链表选择排序

试以单向链表为存储结构实现简单选择排序的算法。 实现递增排序,首先选择一个元素作为第一个比较值,遍历其他所有的元素,如果发现其他元素中有比它小的元素,则交换两个元素,这样每一趟都能找到符合要求的最小值 正经…

Turnitin查重时,论文里面的图片会不会被查到?

在撰写论文的时候,论文里面插入几张图片作为观点和数据的阐述在再正常不过了。但是,一旦涉及到论文查重,事情就变得有点复杂了。许多同学早使用Turnitin检测系统(www.checktoo.com)对论文查重时,就常问题到…

记录交叉编译环境配置--海思开发板的 嵌入式nginx和 php的移植

嵌入式 lnmp搭建的记录 一些交叉编译的配置环境思路分享:P:php编译PHP可能遇到的问题configure阶段:Makefile-make阶段:Makefile-make install阶段: N:Nginx 文章比较水,并没有没解决什么实际问…

现货白银保证金交易要先分析趋势

现货白银是保证金交易品种,买卖过程中可能会涉及数十倍的资金杠杆,所以它对投资者的分析水平和交易水平的要求都比较高,所以在进入这个市场之前,投资者需要先学习一些基本的分析方法,当中可以分为基本面和技术面两大流…

2024年外贸独立站建设首选:WordPress引领市场,助力企业出海

随着全球经济的不断融合与发展,越来越多的企业开始关注海外市场,希望通过建设外贸独立站来扩大品牌影响力和销售额。在众多的内容管理系统(CMS)中,WordPress以其强大的功能、丰富的插件资源和用户友好的操作界面&#…

医学临床预测模型发展新趋势-并联式

医学临床预测模型发展新姿势-并联式 现有的预测模型是对单个结局指标进行分类或者回归,得出最终的结论,而辅助医生进行临床决策。众所周知,临床决策过程中,医生通常会考虑多个结局指标来做出最终的决策;临床研究中也通…

多因子模型的因子分组-克隆巴赫α系数

优质博文:IT-BLOG-CN 在建立我们的Alpha模型之前,我们得先知道什么是Alpha?Alpha是一条或者一系列能够预测股票走势的信息资讯组合。而这每一条非随机的信息资讯,我们称之为多因子模型的因子。多因子模型因子的选择需要避免系统性…

苍穹外卖day1--开发环境搭建

整体结构 前端:管理端(Web) 用户端(小程序) 后端:后端服务(Java) 前端工程基于ngnix运行 启动nginx:双击nginx.exe即可启动nginx服务,访问端口号为80 后端…

智慧浪潮下的产业园区:解读智慧化转型如何打造高效、绿色、安全的新产业高地

随着信息技术的飞速发展,智慧化转型已经成为产业园区发展的重要趋势。在智慧浪潮的推动下,产业园区通过集成应用物联网、大数据、云计算、人工智能等先进技术手段,实现园区的智慧化、高效化、绿色化和安全化,从而打造成为新产业高…

网络安全产品---数据库防火墙/审计

数据库防火墙 防火墙的类型繁多,即使下一代防火墙或者说AI防火墙集成功能再多,我觉得waf与数据库防火墙也有其无法被替代的理由,以此记录我对数据库防火墙的理解 what 数据库防火墙是基于数据库协议分析与访问行为控制的数据库安全防护产品…

ZStack教育云计算解决方案入选高质量数字化转型技术解决方案集

近日,中国信通院“铸基计划”《高质量数字化转型技术解决方案(2023年度)》(以下简称“方案集”)发布,云轴科技ZStack智慧教育云计算解决方案入选《高质量数字化转型技术解决方案集》。 为促进数字化转型相…