Go——多值赋值和短变量声明

2023-05-16

1、 多值赋值

可以一次性声明多个变量,并可以在声明时赋值,而且可以省略类型,但必须遵守一定的规则要求,具体看下面的示例。

  • 如下都是合法的
//相同类型的变量可以在末尾带上类型
var x, y int
var x, y int = 1, 2

//如果不带类型,编译器则可以直接进行类型推断
var x, y = 1, 2
var x, y = 1, "tata'

//不同类型的变量声明和隐式初始化可以使用如下语法
var (
	x int 
	y string
)
  • 如下都是非法的
//多值赋值语句中每个变量后面不能都带上类型
var x int,y int 1,2
var x int,y string 1,"tata"
var x int,y int
var x int,y string

多值赋值的两种格式

  1. 右边是一个返回多值的表达式,可以是返回多值的函数调用,也可以是range对map、slice等函数的操作,还可以是类型断言。例如:
//函数调用
x,y = f()

//range表达式
for k,v :range map {

}

//type assertion
v,ok := i.(xxxx)
  1. )赋值的左边操作数和右边的单一返回值的表达式的个数一样,逐个从左向右依次对左边的操作数赋值。例如:
x, y, z = a, b, c

多值赋值语义

多值赋值看似简化了代码,但相互引用会产生让人困惑的结果。关键是要理解多值赋值的语义,才能消除这种困惑。多值赋值包括两层语义:

  1. 对左侧操作数中的表达式、索引值进行计算和确定,首先确定左侧的操作数的地址:然后对右侧的赋值表达式进行计算,加果发现右侧的表达式计算引用了左侧的变量,则创建临时变量进行值拷贝,最后完成计算。
  2. 从左到右的顺序依次赋值。

看下面的示例:

package main

import "fmt"

func main() {
	x := []int{1, 2, 3}
	i := 0
	i, x[i] = 1, 2 //set i = 1, x[0] = 2
	fmt.Println(i, x)

	x = []int{1, 2, 3}
	i = 0
	x[i], i = 2, 1 //set x[0] = 2, i = 1
	fmt.Println(i, x)

	x = []int{1, 2, 3}
	i = 0
	x[i], i = 2, x[i] // set tmp = x[0], x[0] = 2, i = tmp ==> i = 1
	fmt.Println(i, x)

	x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2
	fmt.Println(x[0])
}

//结果
1 [2 2 3]
1 [2 2 3]
1 [2 2 3]
2

结果分析:

  1. 第8行先计算x[i]中的数组索引i的值,此时i=0,两个被赋值变量是i和x[0],然后从左向右赋值操作i=1,x[0]=2。
  2. 第13行和第8行的逻辑一样。
  3. 第16行先计算赋值语句左右两侧x[i])中的数组索引i的值,此时=0,两个被赋值变量是i和x[0],两个赋值变量分别是2、x[0]。由于x[0]是左边的操作数,所以编译器创建一个临时变量tmp,将其赋值为x[0],然后从左向右依次赋值操作x[0]=2,i=tmp,i的值为1。
  4. )第22行按照从左到右的执行顺序,先执行x[0]=1,然后执行x[0]=2,所以最后x[0]的值为2。

2、短变量的声明和赋值

短变量的声明和赋值是指在G0函数或类型方法内部使用“:=”声明并初始化变量,支持多值赋值,格式如下:

a := va
a,b := va,vb

短变量的声明和赋值的语法要约:

  1. 使用“=”操作符,变量的定义和初始化同时完成。
  2. 变量名后不要跟任何类型名,Go编译器完全靠右边的值进行推导。
  3. 支持多值短变量声明赋值。
  4. 只能用在函数和类型方法的内部。

短变量的声明和赋值中的最容易产生歧义的是多值短变量的声明和赋值,这个问题的根源是Go语言的语法允许多值短变量声明和赋值的多个变量中,只要有一个是新变量就可以使用":="进行赋值。也就是说,在多值段变量的声明和赋值时,至少有一个变量是新创建的局部变量,其他的变量可以复用以前的变量,不是新创建的变量执行的仅仅就是赋值。

package main

func main() {
	//此时main函数作用域里面没有n
	//所以创建的局部变量n
	n, _ := foo()

	//访问的是全局变量n
	g() //0

	//访问的是main函数作用域下的n
	println(n) //1
}

var n int

func foo() (int, error) {
	return 1, nil
}

//访问全局变量n
func g() {
	println(n)
}

通过上例分析得知,a,b:=va,vb什么时候定义新变量,什么时候复用已存在变量有以下规则:

  1. 如果想编译通过,则a和b中至少要有一个是新定义的局部变量。换句话说,在此语句所在代码块中,不能同时预先声明a、b两个局部变量。

  2. 如果在赋值语句a,b:=va,vb所在的代码块中已经存在一个局部变量a,则赋值语句a,b:=va,vb不会创建新变量a,而是直接使用va赋值给已经声明的局部变量a,但是会创建新变
    量b,并将vb赋值给b。

  3. 如果在赋值语句a,b:=va,vb所在的代码块中没有局部变量a和b,但在全局命名空间有变量a和b,则该语句会创建新的局部变量a和b并使用va、vb初始化它们。此时赋值语句
    所在的局部作用域类内,全局的a和b被屏蔽。

赋值操作符“=”和“:=”的区别:

  • “=”不会声明并创建新变量,而是在当前赋值语句所在的作用域由内向外逐层去搜寻变量,如果没有搜索到相同变量名,则报编译错误。
  • “:=”必须出现在函数或类型方法内部。
  • “:=”至少要创建一个局部变量并初始化。
func f() {
	var a, b int
	//如下语句不能通过编译,原因是没有创建新变量,无法使用":="
	a, b := 1, 2
}

func f() {
	var a int
	//如下语能通过编译,a是上调语句声明的a,b是新建的
	a, b := 1, 2
}

func f() {
	//如下语句能够通过编译,a、b都是新创建的
	a, b := 1, 2
}

如何避免“:=”引入的副作用?一个好办法就是先声明变量,然后使用“=”赋值。例如:

func f(){
	var a,b int
	a,b=1,2
}

多值短变量声明赋值“=”的最佳使用场景是在错误处理上。例如:

a, err := f()
if err != nil {
	xxx
}

//此时err可以是已经存在的err变量,只是重新赋值了
b, err := g()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go——多值赋值和短变量声明 的相关文章

随机推荐

  • Get the Job You Want(大学英语综合教程4课文)

    UNIT3 1 Harvey Mackay who runs his own company often interviews applicants for jobs Here he lets us into the secret of w
  • Debian9.5 VNC Server远程桌面配置

    VNC概述 VNC Virtual Network Console 是虚拟网络控制台的缩写 VNC 是一款优秀的远程控制工具软件 xff0c 由著名的 AT amp T 的欧洲研究实验室开发的 VNC 是在基于 UNIX 和 Linux操作
  • 嵌入式常用的英文缩写词汇

    原文地址 xff1a https wenku baidu com view 9d4051f4700abb68a982fb4e html 嵌入式常见英文缩写和英文词汇 搜集中 英文缩写 ARM xff1a Advanced RISC Mach
  • 先安装VS2017再安装VS2015遇到的CMake问题

    先安装了VS2017 xff0c 后来有需求安装VS2015 xff0c 安装VS2015的时候遇到下图问题 xff0c 但是控制面板里面看不到Microsoft Visual C 43 43 2015 Redistributable的项目
  • 粒子群算法优化BP生物能神经网络

    定义 xff1a 粒子群中每个粒子的位置表示BP神经网络当前迭代中权值的集合 xff0c 每个粒子的维数由网络中起连接作用的权值的数量和阈值个数决定 xff0c 以给定训练样本集的神经网络输出误差作为神经网络训练问题的适应度函数 xff0c
  • 实现分布式锁技术:Redisson

    1 需求 Spring分布式项目涉及到定时任务 xff0c 目前解决方案 xff1a xff08 1 xff09 集成quartz xff1b xff08 2 xff09 集成redisson xff0c 由于集成quartz需要涉及到数据
  • nginx支持websocket及websocket部分原理介绍

    nginx支持websocket及websocket部分原理介绍 最近ipc通过websocket与server进行通行 xff0c 经过无法通过nginx进行反向代理 xff0c 只有直连nodejs端口 而且部署到阿里云用了slb之后同
  • Windows下分布式环境搭建以及简单测试

    环境配置 xff1a 解压文件 xff1a Nginx服务器和Tomcat服务器 Tomcat服务器配置 xff1a xff08 conf server xml xff09 Nginx配置 xff1a xff08 conf nginx co
  • Go——Inject库

    1 依赖注入和控制反转 在介绍inject之前先简单介绍 依赖注入 和 控制反转 的概念 正常情况下 xff0c 对函数或方法的调用是调用方的主动直接行为 xff0c 调用方清楚地知道被调的函数名是什么 xff0c 参数有哪些类型 xff0
  • 浅谈SpringBoot核心注解原理

    SpringBoot核心注解原理 今天跟大家来探讨下SpringBoot的核心注解 64 SpringBootApplication以及run方法 xff0c 理解下springBoot为什么不需要XML xff0c 达到零配置 首先我们先
  • Quartus II和Modelsim的联合仿真(详细)

    这篇文章不需要在modelsim中建库 映射 建工程等一些繁琐的步骤 xff0c 直接使用modelsim中的默认work库 使用quartus 43 modelsim联合仿真 首先推荐一篇文章 http www cnblogs com e
  • requests.post处理Content-Type: multipart/form-data的请求

    前几天遇到一个需求 xff0c 要调用一个接口发送请求 xff0c 抓包之后得到的数据是这样的 上网看了一些资料得知 xff0c 原来这个接口的数据是通过multipart form data格式传过去的 xff0c multipart f
  • 上一步,下一步(撤销和恢复)

    var data 61 data count 61 0 data list 61 function regain function handleSaveCss 获取workspace body里面的内容 var c 61 34 worksp
  • Ubuntu下dpkg安装软件遇到包依赖问题的处理方法

    造冰箱的大熊猫 64 cnblogs 2019 9 10 向灵魂工程师致敬 xff01 在Ubuntu环境下通过dpkg命令安装deb包时 xff0c 如果遇到包依赖问题 xff0c 如 sudo dpkg i xxx deb Readin
  • Ubuntu18优化桌面版的运行速度

    一 刚开始使用Ubuntu18后 xff0c 感觉开机和运行速度都不理想 xff0c 通过改变一些配置可以提高下用户体验感 二 改变一些配置 a 使用Preload预加载 sudo apt install preload y b 禁用不必要
  • Debian安装mplayer,解决没有声音及声卡独占问题

    通过软件中心可以安装Gnome mplayer 本来以为这样这个播放器已经是 万能 的了 xff0c 但是最近下载了几个 mkv的电影 却发现Gnome mplayer没有办法打开 感觉很失望 在网上找了一番后 说只要下载源代码自己安装就行
  • CentOS7中安装MySQL5.7

    安装必要的组件 yum install y autoconf automake imake libxml2 devel expat devel cmake gcc gcc c 43 43 libaio libaio devel bzr bi
  • 20190708新的开始

    题目描述 发展采矿业当然首先得有矿井 xff0c 小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井 xff0c 但他似乎忘记考虑的矿井供电问题 为了保证电力的供应 xff0c 小 FF 想到了两种办法 xff1a 在这一
  • Debian安装JDK

    sudo tar zxvf jdk 8u60 linux x64 tar gz C usr local vi bashrc export JAVA HOME 61 usr local jdk1 8 0 60 export JRE HOME
  • Go——多值赋值和短变量声明

    1 多值赋值 可以一次性声明多个变量 xff0c 并可以在声明时赋值 xff0c 而且可以省略类型 xff0c 但必须遵守一定的规则要求 xff0c 具体看下面的示例 如下都是合法的 span class token comment 相同类