06 | 程序实体的那些事儿 (下)
06 | 程序实体的那些事儿 (下)
讲述:黄洲君
时长11:14大小7.70M
典型回答
问题解析
知识扩展
总结
思考题
赞 19
提建议
精选留言(44)
- 思想的宇屋置顶2018-12-29真棒,这篇涉及到了自学go的gopher比较难涉及到的计算机基础和细节 如补码,类型转换异常时的“❓”14
- pines2018-08-24正数的补码等于原码,负数的补码才是反码+1113
- 陈悬高2018-10-10对于大型的代码库来说,能够重构其整体结构是非常重要的,包括修改某些 API 所属的包。大型重构应该支持一个过渡期:从旧位置和新位置获得的 API 都应该是可用的,而且可以混合使用这些 API 的引用。Go 已经为常量、函数或变量的重构提供了可行的机制,但是并不支持类型。类型别名提供了一种机制,它可以使得 oldpkg.OldType 和 newpkg.NewType 是相同的,并且引用旧名称的代码与引用新名称的代码可以互相操作。 考虑将一个类型从一个包移动到另一个包中的情况,比如从 oldpkg.OldType 到 newpkg.NewType。可以在包 oldpkg 中指定一个新类型的别名 type OldType = newpkg.NewType,这样以前的代码都无需修改。展开41
- 咖啡色的羊驼2018-08-24最开始写go时候也在string上遇到过一个小坑。 由于是之前是phper,习惯性认为go中len("我")应该等于1,后面发现这个遇到字符串时候代表字节数。共 7 条评论30
- 胖子(李杰)2019-05-16php 里面的strlen('你') 也不是1 mb_strlen('你') 才是 1共 1 条评论17
- 李皮皮皮皮皮2018-08-241.通过类型断言获取变量实际类型value,ok=x.(T),ok表示是否是正确的类型,value是成功转换后的值,但返回值形式不建议使用,可能会导致panic 2.go不同类型直接不能相互赋值,不存在隐式类型转换,必须显式强转 3.type newType = oldType定义类型别名,type newType oldType定义新类型13
- 🄽🄸🅇🅄🅂2018-10-11这节课,是从开始学习该专栏以来,最有价值的一节,没有之一! 希望剩下的课程,都能像这节课这样有价值!
作者回复: 尽量做到能让大多数人满意:)
12 - BitInit2019-03-20对于var str string = "hello 你好",使用len(str)结果是12,因为len(str)显示的string底层字节大小。如果需要str的大小,方法一是len([]rune(str)),将string转为rune切片,方法二是utf8.RuneCountInString(str)。对string进行range遍历时,是以unicode编码遍历的。共 2 条评论11
- hello peter2018-08-24@咖啡色的羊驼 我也是phper,php中strlen('我')的结果应该是3,和go一样,你这习惯应该是js的吧共 2 条评论5
- mkii2021-06-09type A struct { B *B } func (a *A) Print() { a.B.Print() } type B struct { str string } func (b *B) Print() { //if b.str == ""{ fmt.Println("1234") //}else{ // fmt.Println("str is:",b.str) //} } func TestAPrint(t *testing.T) { a := &A{nil} a.Print() } 老师,为什么print函数这里不会Panic呀?展开
作者回复: 首先需要明确,结构体类型 A 中的字段 B(为了区分,以下称为 b 吧)的类型是一个“指针类型”,即 *B 。而结构体类型 B 携带了一个“指针方法” Print 。这里的“指针类型”和“指针方法”是关键。 即便 a 的字段 b 是 nil,但是 b 本身的“方法集合一直存在”(即类型 *B 的方法集合),只不过它的值为 nil 罢了。 正是由于 a 中的字段 b 的“方法集合一直存在”,因此a.b.Print() 这条链路才能走通。又由于类型 B 的方法 Print 的接收者类型为 *B ,所以在该方法执行的时候才不需要为了求接收者 b 的值而进行取值操作(即从 *B 到 B 的转换)。你可以想象一下,若 B 有另外一个方法 func (b B) Show() ,那么执行 a.b.Show() 会怎样。 你可以再写一些代码,如: var b1 *B = nil switch interface{}(b1).(type) { case C: fmt.Println("C") default: fmt.Println("?") } 执行这段代码会打印出“C”。那你觉得为什么Go编译器能够知道 interface{}(b1) 的类型是 C 呢?它就是根据 b1 的方法集合来判断的啊。 无论 b 和 b1 的值是什么,只要它们有类型,它们的方法集合就是固定的。它们的“方法集合一直存在”!
5 - 极客—月2021-05-17怎样判断变量类型 => 类型断言 格式:value, ok := x.(T) 其中T是判断类型,x是要判断类型的值【x必须是接口类型】。 ok是类型判断的结果,如果ok是true,则value就是x转换为T类型的值。 如果ok是false,value会被赋值为nil。 当写成value := x.(T)时,即省去ok,若转换不成功则会报panic {}在Go中可表示: 1. 空代码块 2. 不包含任何内容的数据类型,如:struct{},interface{} 3. 不包含任何元素的集合类型,如: []string{},map[int]string{} 类型字面量:表示数据类型本身的若干个字符,如[]string表示string的切片类型,map[int]string表示key为int类型,value为string类型的字典类型。 类型转换的三个小坑: 一、对于整数类型值、整数常量之间的类型转换,只要源值在目标类型的可表示范围内就是合法的。 需注意的是: 1. 当整数值的类型的有效范围由宽变窄时,只需在补码形式下截掉一定数量的高位二进制数即可 2. 当把一个浮点数类型的值转换为整数类型值时,前者的小数部分会被全部截掉 【这里涉及原码反码补码的知识,可以自己算下int16位的-255转成int8会是多少】 二、整数值转换为string类型可行,但需注意被转换的整数值应该可以代表一个有效的 Unicode 代码点 比如:string(-1) 得到字符'�',字符'�'是 Unicode 标准中专用于替换未知的以及无法展示的字符 因为-1无法代表一个有效的 Unicode代码点 三、 关于string类型与各种切片类型之间的互转: 1. 值从string类型向[]byte类型转换时代表以 UTF-8 编码的字符串会被拆分成零散、独立的字节。例如中文会被拆分为三个字节 2. 值从string类型向[]rune类型转换时代表字符串会被拆分成一个个 Unicode 字符 别名类型:type MyString = string 类型再定义:type Mystring2 string 【string可称为MyString2的潜在类型】 【上面俩的差别就在于多了个"="】 潜在类型相同的不同类型的值之间可互相转换,但不能赋值、比较 集合类型[]MyString2与[]string则不能互转【string是MyString2的潜在类型,但[]MyString2的潜在类型是[]MyString2,而[]string的潜在类型是[]string】展开5
- 沐夜星光2020-01-06既然有了别名类型,为什么还要再搞个别名再定义,两者的应用场景有什么区别?
作者回复: 两者都是为了隔离变化。 别名类型“另起炉灶”的只是名字,主要是向上层应用隐藏下层类型的真实名称。这样一来,下层类型体系在重构的时候就可以换名字了(不会影响到上层代码)。 类型再定义更彻底一些。主要是为了另外构建一个与潜在类型有所关联(有一定的互操作性)但又不同的类型。基于这个新类型,我们可以构建另外一套操作或者类型体系,而不用去改动潜在类型(或者说潜在类型所在的体系)。
共 3 条评论5 - 我来也2018-08-24类型转换感觉跟c差不多。 类型别名,我知道的三处优点:1.名字可以取的更通俗易懂;2:需要修改数据类型时,只用改定义的那一处地方;3:可以很方便的添加特有方法,以实现某些接口。4
- 扩散性百万咸面包2020-04-08其中的x可以是一个变量,也可以是一个代表值的字面量(比如1.23和struct{}{}),还可以是一个表达式。 struct{}{} 的意思是声明一个空结构然后立刻初始化?
作者回复: 对, struct{} 是空结构体类型,struct{}{} 是对它的实例化。其实这种实例化总会返回相同的值。你可以把 struct{} 视为单例类型。
3 - 传说中的成大大2020-03-02一门新的技术的产生或者语言新特性的产生总是为了解决一些现有的比较棘手的问题 所以我在想 类型别名和 类型重定义及潜在类型 为什么会同时存在? 然后提到潜在类型 那么语言自带的类型 比如string是否有潜在类型 如果有是否就是它本身?
作者回复: “类型别名”和“类型重定义”其实属于在Go语言的发展过程中相继出现的两个类似产物。但鉴于它们在功能上还是有明显差别的,所以理解起来也算容易。 “潜在类型”其实更多的是在语言词法分析方面起作用。从程序开发的角度讲,它几乎只与类型转换相关。“潜在类型”是Go语言规范中的死规定,所以记下来就好了。
4 - Hector2019-05-10string可以被称为MyString2的潜在类型,那他们的区别到底在哪里呢?底层时做的复制动作,但是指针存放的地址不同吗
作者回复: 我在文章里说了:“潜在类型相同的不同类型的值之间是可以进行类型转换的”。这属于语法规则。 它们虽然代表着不同的类型,但本质上是同源的。也就是说,它们的底层结构是相同的。在这样情况下,在类型转换时值会被复制,即两个值会在不同的内存地址上。
3 - 勇敢的心2019-01-05要成为kubernetes玩家,必须好好学习go语言!共 1 条评论4
- 田佳伟2018-09-06首先你要知道,整数在 Go 语言以及计算机中都是以补码的形式存储的 这句话应该是:首先你要知道,负数在 Go 语言以及计算机中都是以补码的形式存储的 吧😄
作者回复: 正数的补码等于其自身。
3 - LubinLew2020-06-02类型定义这部分有点太抽象了,这个文章中用华氏和摄氏的例子非常棒,虽然华氏和摄氏的潜在类型相同,但是他们之间进行直接比较是没有意义的。 https://www.jianshu.com/p/a02cf41c05202
- NoTryNoSuccess2019-06-27container := map[int]string{0: "zero", 1: "one", 2: "two"} value, _ := interface{}(container).(int) 其实这样也不会报错呀,且value为0并不为nil,其中int也可以为其他任何与目标类型map不一致的类型。共 3 条评论2