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 -->intdefined 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 A5B0 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关键字定义类型的时候,会遇到一些问题,如下:func main(){var i int 2pushInt(i) } type MyInt int //基于int定义MyInt func pushInt(i MyInt){}结果:调用函数pushInt报错 cannot use i (variab…...
外盘国际期货招商:原油市场热点话题
原油市场热点话题 问:目前美国原油库存如何? 答:EIA原油库存数据显示,由于美国炼油厂季节性检修,开工率继续下降,原油库存连续九周增长至2021年5月份以来最高水平,同期美国汽油库存减少而精炼…...
[蓝桥杯 2018 省 A] 付账问题 贪心题
几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。现在有 n 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出…...
微机原理复习(周五),计算机组成原理图
1.计算机由运算器,控制器,存储器,输入设备,输出设备等5大基本部件组成。 2.冯诺依曼提出存储设计思想是:数字计算机的数制采用二进制,存储程序,程序控制。 3.计算机的基本组成框图:…...
用了10年Postman,意想不到它的Mock功能也如此强大
最近在做一些app,前后端分离的开发模式是必须的。一直用的python flask做后端的快速POC,python本身就是一门胶水语言,开发起来方便快捷,而flask又是一个极简的webserver框架(比Django简洁)。但在这里推荐的…...
项目重构,从零开始搭建一套新的后台管理系统
背景 应公司发展需求,我决定重构公司的后台管理系统,从提出需求建议到现在的实施,期间花了将近半个月的时间,决定把这些都记录下来。 之前的后台管理系统实在是为了实现功能而实现的,没有考虑到后期的扩展性…...
day20_Map
今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、比较器排序 三、Collections 四、Map 五、HashMap 六、TreeMap 零、 复习昨日 HashSet 不允许重复元素,无序 HashSet去重原理: 先比较hashco…...
localStorage和sessionStorage
目录 一、localStorage和SessionStorage在哪里,是什么 二、localStorage和sessionStorage区别 三、localStorage常用方法 四、sessionStorage常用方法 一、localStorage和SessionStorage在哪里,是什么 【1】在浏览器开发者工具的Application栏目里&…...
IP地址,子网掩码,网段 概念详解
文章目录1. 子网掩码1.1 子网掩码的概念及作用1.2 子网掩码的组成1.3 子网掩码的表示方法1.4 为什么要使用子网掩码?1.5 子网掩码的分类2. 子网掩码和IP地址的关系2.1 根据掩码确定网段IP地址是以 网络号和 主机号来标示网络上的主机的,我们把网络号相同…...
数影周报:动视暴雪疑似数据泄露,数据出境安全评估申报最新进展
本周看点:动视暴雪疑似员工敏感信息及游戏数据泄露;谷歌云计算部门:两名员工合用一个工位;数据出境安全评估申报最新进展;TikTok Shop东南亚商城在泰国和菲律宾公布;智己汽车获九大金融机构50亿元贷款签约.…...
Web安全最详细学习路线指南,从入门到入职(含书籍、工具包)
在这个圈子技术门类中,工作岗位主要有以下三个方向: 安全研发 安全研究:二进制方向 安全研究:网络渗透方向 下面逐一说明一下. 第一个方向:安全研发 你可以把网络安全理解成电商行业、教育行业等其他行业一样&#x…...
ChatGPT?听说Biying把它下架了
ChatGPT被玩疯了,开始放飞自我 ChatGPT版微软必应上线不到10天…就被网友玩坏了 先说这个词,放飞自我,什么东西才会放飞自我? 人放飞自我,人?你确定是人? 所以让我们来把上面的句子改写一下。…...
中电金信:金融数字化转型路在何方?这里有答案
近期,媒体大数网整合了业内10份研究报告,详解金融数字化转型的思路、方法与路径。其中「中国电子金融级数字底座“源启”白皮书」也被收录其中。让我们一同阅读文章,探究金融数字化转型相关问题的答案吧。 当前,金融科技正在回归…...
【Leedcode】数据结构中链表必备的面试题(第五期)
【Leedcode】数据结构中链表必备的面试题(第五期) 文章目录【Leedcode】数据结构中链表必备的面试题(第五期)1.题目2.思路图解(1)第一步:复制每一个结点,插入到原结点和下一个结点之…...
ECDH secp256k1 集成
在Android 原生api是不支持secp256k1算法的,所以要先集成以下库: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:…...
工单模型的理解与应用
工单(任务单)模型的定义 工单模型是一种分派任务的方法,可以用来跟踪、评估和报告任务的完成情况。它通常用于针对特定目标的重复性任务或项目,以确保任务能够按时完成并符合期望的标准。 工单模型的基本流程为:提…...
Python年利率计算器【N日年化收益率】
现在有闲钱的人,按照聪明等级从低到高排序应该是钱买股票,一年利率约为-20%钱放银行活期,年利率约为0.3%钱放银行定期,一年利率约为1.5%钱放余额宝(支付宝)或零钱通(微信)࿰…...
3年测试拿8K,被校招来的实习生反超薪资,其实你在假装努力
最近朋友给我分享了一个他公司发生的事 大概的内容呢:公司一位工作3年的测试工资还没有新人高,对此怨气不小,她来公司辛辛苦苦三年,三年内迟到次数都不超过5次,每天都是按时上下班,工作也按量完成…...
因子分析计算权重
因子分析两类权重计算方法总结 案例背景 疫情爆发以来,越来越多的人为了避免线下与人接触,选择了线上购买生活必需品。网购虽然方便快捷,但是随着订单压力的增加,物流问题也随之出现,近期有很多卖家收到物流投诉的问题…...
国家调控油价预测案例+源码
项目git地址:https://github.com/Boris-2021/Oil-price-control-forecast 使用已知的历史数据:日期、汇率、布伦特、WTI、阿曼原油价格,预测下一个调价周期中的汽油、柴油零售限价的调价价格。 一. 需求 1.1 需求说明 使用已知的历史数据&a…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
