当前位置: 首页 > news >正文

Go语言规范中的可赋值

了解可赋值规范的重要性

当使用type关键字定义类型的时候,会遇到一些问题,如下:

func main(){var i int = 2pushInt(i) }
type MyInt int //基于int定义MyInt
func pushInt(i MyInt){}结果:调用函数pushInt报错
cannot use i (variable of type int) 
as MyInt value in argument to pushIntcompilerIncompatibleAssign

而相似的,这种调用就不会出错:

func main(){var i []int = []int{2,3,4}pushInt(i)}type MyInt []int //基于[]int 定义MyInt
func pushInt(i MyInt){}结果:正常编译运行!!!

go语法中的赋值无处不在,赋值操作、调用方法时的receiver赋值、调用方法的parameter赋值、方法返回值的接收变量赋值,赋值即值拷贝,这个大家都懂,可是赋值的类型约束是什么?

赋值原则其实很简单

1、类型相同可以进行赋值
2、类型不同的情况,至少有一个是unnamed type,且底层类型必须兼容。

下面会慢慢讲解。

go语言规范定义

go语言规范中对可赋值的描述比较复杂,说到底就是上面的2个原则,我们先大概看一下规范内容,然后等阐明什么叫类型相同,什么叫底层类型相同,在回过头来理解该规范。

A value x of type V is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:

  • V and T are identical.

  • V and T have identical underlying types but are not type parameters and at least one of V or T is not a named type.

  • V and T are channel types with identical element types, V is a bidirectional channel, and at least one of V or T is not a named type.

  • T is an interface type, but not a type parameter, and x implements T.

  • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type, but not a type parameter.

  • x is an untyped constant representable by a value of type T.

Additionally, if x's type V or T are type parameters, x is assignable to a variable of type T if one of the following conditions applies:

  • x is the predeclared identifier nil, T is a type parameter, and x is assignable to each type in T's type set.

  • V is not a named type, T is a type parameter, and x is assignable to each type in T's type set.

  • V is a type parameter and T is not a named type, and values of each type in V's type set are assignable to T.

什么叫类型相同

1、named type,有名字的类型,只有名称相同才能称为类型相同

named的type包括

  • predeclared type,即程序预声明的类型,如int byte run string等,这些都是有名字的。

var x int = 20 //x的类型是named type -->int
  • defined type,即通过type关键字定义的类型,定义时根据语法是必须要给定名字的。(注意type declaration和type definition的区别)

type Dog struct{} //类型名字为Dog
type Dog int //类型名字为Dogtype Dog = int //类型名字为int(Dog只是个别名)
type Dog = struct{} //该类型是unnamed(Dog只是个别名)
  • type parameter,类型参数是泛型中的概念,其定义了新的类型,例如[T ~int],类型名为T,底层类型为int(底层类型后面讲)

func name[T ~string](dogName T){} //定义了一个新的类型T
//注意T是一个类型,而func name(T string)中,T是一个变量。
2、literal type,字面量类型没有名称,只要结构相同,类型就相同

composite类型都可以用字面量定义新的类型,如slice channel等的类型都可以用literal来定义,如下列举了几个literal类型定义:

    var x func(string) int = func(s string) int {return 1} //functionvar x struct{ name string } = struct{ name string }{"name"} //structvar x []int = []int{1,2,3} //slicevar x [3]int = [3]int{1,3,4} //arrayvar x map[int]int = make(map[int]int) //mapvar x chan int = make(chan int) //channelnum := 23var x *int = &num //pointervar x interface{String() stringName() string} = Inner{"name"} //interface

我们发现其实 指针类型、chan、map、array、slice的类型定义,我们平时都是使用unnamed的literal type 形式。因为比较方便。如果我们使用named type反而会比较麻烦

type MyMap map[int]int //这样定义类型就比较麻烦

3、规范中对类型相同的描述

以上两种已经描述何为类型相同,规范中是这样描述的:

A named type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types. In detail:

  • Two array types are identical if they have identical element types and the same array length.

  • Two slice types are identical if they have identical element types.

  • Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical types, and identical tags. Non-exported field names from different packages are always different.

  • Two pointer types are identical if they have identical base types.

  • Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.

  • Two interface types are identical if they define the same type set.

  • Two map types are identical if they have identical key and element types.

  • Two channel types are identical if they have identical element types and the same direction.

  • Two instantiated types are identical if their defined types and all type arguments are identical.

4、小试牛刀(规范中的小练习)

以下类型哪些相同

type (A0 = []stringA1 = A0A2 = struct{ a, b int }A3 = intA4 = func(A3, float64) *A0A5 = func(x int, _ float64) *[]stringB0 A0B1 []stringB2 struct{ a, b int }B3 struct{ a, c int }B4 func(int, float64) *B0B5 func(x int, y float64) *A1C0 = B0D0[P1, P2 any] struct{ x P1; y P2 }E0 = D0[int, string]
)

相同的类型:

A0, A1, and []string
A2 and struct{ a, b int }
A3 and int
A4, func(int, float64) *[]string, and A5
B0 and C0
D0[int, string] and E0
[]int and []int
struct{ a, b *B5 } and struct{ a, b *B5 }
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5

B0 and B1 are different because they are new types created by distinct type definitions; func(int, float64) *B0 and func(x int, y float64) *[]string are different because B0 is different from []string; and P1 and P2 are different because they are different type parameters. D0[int, string] and struct{ x int; y string } are different because the former is an instantiated defined type while the latter is a type literal (but they are still assignable)

什么叫底层类型相同

什么叫底层类型

每种类型都有其底层类型

  • 上面提到的predeclared类型和literal类型其底层就是其本身

var x int //变量x的类型是predeclared 的int,int的底层类型是int
var x []int //类型是literal的[]int,其底层类型是[]int
  • 指向类型的底层类型,是其指向的类型的底层类型。有点拗口,上栗子

type MyInt int //MyInt指向int,int的底层类型是int,那么结果是int
type YourInt MyInt //YourInt指向MyInt,那么就是MyInt的底层类型,那么结果就是int
type HisInt YourInt //HisInt指向YourInt,以此类推,那么结果就是int
  • 类型参数的底层类型,是其约束类型。

func name[T ~string](n  T){}//类型参数定义了新的类型T,T的底层类型就是string

知道底层类型是什么,那么按第一小节“什么叫类型相同”中的规则进行对比,即可知道两个类型的底层类型是否相同。

回过来看可赋值的规范定义

下面会对规范中可赋值定义进行一句句解释:

A value x of type V is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:

这一部分讲解非type parameter(类型参数)的情形:

  • V and T are identical.

类型相同,可以赋值
  • V and T have identical underlying types but are not type parameters and at least one of V or T is not a named type.

不是类型参数,底层类型相同,如果只有一个unnamed type那么底层类型相同,两个
都是unnamed type的话是相同类型。
  • V and T are channel types with identical element types, V is a bidirectional channel, and at least one of V or T is not a named type.

channel元素相同,底层数据类型相同。如果一个unnamed type的话,那么底层数据相同。如果两个都是
unnamed type的话,那么底层数据相同,甚至是类型完全相同。
var c <- chan int = make(chan int) //类型不同,但底层类型相同
var c chan int = make(chan int) //类型相同
  • T is an interface type, but not a type parameter, and x implements T.

x和T必须有is a的关系。
  • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type, but not a type parameter.

x是nil,因为nil是预声明标识符,而不是类型。
可以赋值给pointer,function....(引用类型和interface类型)
  • x is an untyped constant representable by a value of type T.

x是untyped int ,是unnamed。但是和int32 底层类型相同,所以可以赋值
const x = 1 << 20 //x在初始化的时候是untyped int(x的取值范围可以超过 1<<64的而x处不会报错)
func main() {var y int32 = x}

这一部分讲解type parameter的情形:

Additionally, if x's type V or T are type parameters, x is assignable to a variable of type T if one of the following conditions applies:

  • x is the predeclared identifier nil, T is a type parameter, and x is assignable to each type in T's type set.

x是nil是标识符而不是named type,T是type parameter有名字,类型不同。
T类型参数的类型集是指针类型,可以接受nil
func name3[X *int](age X) {age = nil
}
  • V is not a named type, T is a type parameter, and x is assignable to each type in T's type set.

V是unnamed那么就不会和T的类型不同,底层类型相同即可
func name[X ~int](age X) {a := 20 + agefmt.Println(a)age = 30 // age = a会报错,因为a是named类型,而age = 30就不会报错
}
  • V is a type parameter and T is not a named type, and values of each type in V's type set are assignable to T.

age是type parameter有unnamed的,而x是literal没名字,类型不同,但底层类型一样
func name2[X IntArr](age X) {var x map[int]int = age 
}
type IntArr map[int]int

完全符合我们的可赋值原则

1、类型相同可以进行赋值

2、类型不同的情况,至少有一个是unnamed type,且底层类型必须兼容。

描述可能不够准确,望网络大佬们指正。🙅

相关文章:

Go语言规范中的可赋值

了解可赋值规范的重要性当使用type关键字定义类型的时候&#xff0c;会遇到一些问题&#xff0c;如下&#xff1a;func main(){var i int 2pushInt(i) } type MyInt int //基于int定义MyInt func pushInt(i MyInt){}结果&#xff1a;调用函数pushInt报错 cannot use i (variab…...

外盘国际期货招商:原油市场热点话题

原油市场热点话题 问&#xff1a;目前美国原油库存如何&#xff1f; 答&#xff1a;EIA原油库存数据显示&#xff0c;由于美国炼油厂季节性检修&#xff0c;开工率继续下降&#xff0c;原油库存连续九周增长至2021年5月份以来最高水平&#xff0c;同期美国汽油库存减少而精炼…...

[蓝桥杯 2018 省 A] 付账问题 贪心题

几个人一起出去吃饭是常有的事。但在结帐的时候&#xff0c;常常会出现一些争执。现在有 n 个人出去吃饭&#xff0c;他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是&#xff0c;所有人带的钱的总数是足够付账的&#xff0c;但现在问题来了&#xff1a;每个人分别要出…...

微机原理复习(周五),计算机组成原理图

1.计算机由运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备&#xff0c;输出设备等5大基本部件组成。 2.冯诺依曼提出存储设计思想是&#xff1a;数字计算机的数制采用二进制&#xff0c;存储程序&#xff0c;程序控制。 3.计算机的基本组成框图&#xff1a…...

用了10年Postman,意想不到它的Mock功能也如此强大

最近在做一些app&#xff0c;前后端分离的开发模式是必须的。一直用的python flask做后端的快速POC&#xff0c;python本身就是一门胶水语言&#xff0c;开发起来方便快捷&#xff0c;而flask又是一个极简的webserver框架&#xff08;比Django简洁&#xff09;。但在这里推荐的…...

项目重构,从零开始搭建一套新的后台管理系统

背景 应公司发展需求&#xff0c;我决定重构公司的后台管理系统&#xff0c;从提出需求建议到现在的实施&#xff0c;期间花了将近半个月的时间&#xff0c;决定把这些都记录下来。 之前的后台管理系统实在是为了实现功能而实现的&#xff0c;没有考虑到后期的扩展性&#xf…...

day20_Map

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、比较器排序 三、Collections 四、Map 五、HashMap 六、TreeMap 零、 复习昨日 HashSet 不允许重复元素,无序 HashSet去重原理: 先比较hashco…...

localStorage和sessionStorage

目录 一、localStorage和SessionStorage在哪里&#xff0c;是什么 二、localStorage和sessionStorage区别 三、localStorage常用方法 四、sessionStorage常用方法 一、localStorage和SessionStorage在哪里&#xff0c;是什么 【1】在浏览器开发者工具的Application栏目里&…...

IP地址,子网掩码,网段 概念详解

文章目录1. 子网掩码1.1 子网掩码的概念及作用1.2 子网掩码的组成1.3 子网掩码的表示方法1.4 为什么要使用子网掩码&#xff1f;1.5 子网掩码的分类2. 子网掩码和IP地址的关系2.1 根据掩码确定网段IP地址是以 网络号和 主机号来标示网络上的主机的&#xff0c;我们把网络号相同…...

数影周报:动视暴雪疑似数据泄露,数据出境安全评估申报最新进展

本周看点&#xff1a;动视暴雪疑似员工敏感信息及游戏数据泄露&#xff1b;谷歌云计算部门&#xff1a;两名员工合用一个工位&#xff1b;数据出境安全评估申报最新进展&#xff1b;TikTok Shop东南亚商城在泰国和菲律宾公布&#xff1b;智己汽车获九大金融机构50亿元贷款签约.…...

Web安全最详细学习路线指南,从入门到入职(含书籍、工具包)

在这个圈子技术门类中&#xff0c;工作岗位主要有以下三个方向&#xff1a; 安全研发 安全研究&#xff1a;二进制方向 安全研究&#xff1a;网络渗透方向 下面逐一说明一下. 第一个方向&#xff1a;安全研发 你可以把网络安全理解成电商行业、教育行业等其他行业一样&#x…...

ChatGPT?听说Biying把它下架了

ChatGPT被玩疯了&#xff0c;开始放飞自我 ChatGPT版微软必应上线不到10天…就被网友玩坏了 先说这个词&#xff0c;放飞自我&#xff0c;什么东西才会放飞自我&#xff1f; 人放飞自我&#xff0c;人&#xff1f;你确定是人&#xff1f; 所以让我们来把上面的句子改写一下。…...

中电金信:金融数字化转型路在何方?这里有答案

近期&#xff0c;媒体大数网整合了业内10份研究报告&#xff0c;详解金融数字化转型的思路、方法与路径。其中「中国电子金融级数字底座“源启”白皮书」也被收录其中。让我们一同阅读文章&#xff0c;探究金融数字化转型相关问题的答案吧。 当前&#xff0c;金融科技正在回归…...

【Leedcode】数据结构中链表必备的面试题(第五期)

【Leedcode】数据结构中链表必备的面试题&#xff08;第五期&#xff09; 文章目录【Leedcode】数据结构中链表必备的面试题&#xff08;第五期&#xff09;1.题目2.思路图解&#xff08;1&#xff09;第一步&#xff1a;复制每一个结点&#xff0c;插入到原结点和下一个结点之…...

ECDH secp256k1 集成

在Android 原生api是不支持secp256k1算法的&#xff0c;所以要先集成以下库&#xff1a;implementation com.madgag.spongycastle:core:1.58.0.0compile com.madgag.spongycastle:prov:1.54.0.0compile com.madgag.spongycastle:pkix:1.54.0.0compile com.madgag.spongycastle:…...

工单模型的理解与应用

工单&#xff08;任务单&#xff09;模型的定义 工单模型是一种分派任务的方法&#xff0c;可以用来跟踪、评估和报告任务的完成情况。它通常用于针对特定目标的重复性任务或项目&#xff0c;以确保任务能够按时完成并符合期望的标准。   工单模型的基本流程为&#xff1a;提…...

Python年利率计算器【N日年化收益率】

现在有闲钱的人&#xff0c;按照聪明等级从低到高排序应该是钱买股票&#xff0c;一年利率约为-20%钱放银行活期&#xff0c;年利率约为0.3%钱放银行定期&#xff0c;一年利率约为1.5%钱放余额宝&#xff08;支付宝&#xff09;或零钱通&#xff08;微信&#xff09;&#xff0…...

3年测试拿8K,被校招来的实习生反超薪资,其实你在假装努力

最近朋友给我分享了一个他公司发生的事 大概的内容呢&#xff1a;公司一位工作3年的测试工资还没有新人高&#xff0c;对此怨气不小&#xff0c;她来公司辛辛苦苦三年&#xff0c;三年内迟到次数都不超过5次&#xff0c;每天都是按时上下班&#xff0c;工作也按量完成&#xf…...

因子分析计算权重

因子分析两类权重计算方法总结 案例背景 疫情爆发以来&#xff0c;越来越多的人为了避免线下与人接触&#xff0c;选择了线上购买生活必需品。网购虽然方便快捷&#xff0c;但是随着订单压力的增加&#xff0c;物流问题也随之出现&#xff0c;近期有很多卖家收到物流投诉的问题…...

国家调控油价预测案例+源码

项目git地址&#xff1a;https://github.com/Boris-2021/Oil-price-control-forecast 使用已知的历史数据&#xff1a;日期、汇率、布伦特、WTI、阿曼原油价格&#xff0c;预测下一个调价周期中的汽油、柴油零售限价的调价价格。 一. 需求 1.1 需求说明 使用已知的历史数据&a…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...

goreplay

1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具&#xff0c;可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长&#xff0c;测试它所需的工作量也会呈指数级增长。GoRepl…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...

计算机系统结构复习-名词解释2

1.定向&#xff1a;在某条指令产生计算结果之前&#xff0c;其他指令并不真正立即需要该计算结果&#xff0c;如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方&#xff0c;那么就可以避免停顿。 2.多级存储层次&#xff1a;由若干个采用不同实现技术的存储…...

aurora与pcie的数据高速传输

设备&#xff1a;zynq7100&#xff1b; 开发环境&#xff1a;window&#xff1b; vivado版本&#xff1a;2021.1&#xff1b; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程&#xff0c;pc通过pcie传输给fpga&#xff0c;fpga再通过aur…...