Go Type System(一)

Overview of Go Type System

  • Go由哪几种类型组成?

    • Built-in Basic Types
      • 包括:string, bool, float32, float64, complex64, complex128, uint8(byte), uint16, uint32, uint64, int8, int16, int32(rune), int64, int。共计17种类型。
    • Composite Types
      • 包括:pointer, function, interface, struct, map, slice, array, channel。共计8种类型。
    • Unsafe Pointer Types(由标准库中unsafe包提供)。
    • 综上,Go类型系统由(17 + 8 + 1) == 26种类型构成。
  • 什么是Type Literal?

    • 它是表示(denote)复合类型的一种形式。比如map[int]int, *int, []int等。
    • 它是Undefined Type,因为type T map[int]int,T本身就可以表示一种特定类型。
  • 什么是Type Declaration

    • 它也被称为Type DefinitionType Definition Declaration。格式为type NewTypeName SourceType
    • 不同的Type Declaration定义的多个类型一定是不同的类型。
    • NewTypeNameSourceType是两种不同的类型。
    • NewTypeNameSourceType拥有相同的Underlying Type。两者之间可以进行显式类型转换。
    • Type Declaration可以在函数内部使用。
  • 什么是Type Alias Declaration

    • 格式:type table = map[string]int
    • 它没有定义新的类型,仅仅给map[string]int起了一个别名。
    • Type Alias Declaration也可以在函数内部使用
  • 什么是Defined Types?什么是Undefined Types

    • 所有的Built-in Basic Types都是Defined Types
    • 通过Type Declaration定义的类型是Defined Types
    • 其它类型为Undefined Types
    • Defined Types等价于Named TypesUndefined Types等价于Unnamed Types
  • 什么是Underlying Types

    • Built-in Basic TypesUnderlying Type是它们本身
    • Unsafe Pointer TypesUnderlying Type是它们本身
    • Undefined TypesUnderlying Type是它们本身
    • type NewTypeName SourceType NewTypeName和SourceType拥有相同的Underlying Type
  • 什么是Value?

    • Value有多种表示方式,例如Value Literal(也被称为unnamed constants)、Named ConstantsVariablesExpressions
    • 每种类型都会有一个Zero Value,比如function, pointer, interface, map, slice, channelZero Valuenil,数字类型的Zero Value是0。
    • Value又可分为Untyped ValueTyped Valuevar i int8 = 10之所以是合法的,就是因为10就是Untyped Value。反证法:如果10是Typed Value(假如是int),那么这就违反了不同类型之间转换的规则。Untyped Values一般会有一个默认类型,例如""的默认类型是string, 10的默认类型是int,但是nil没有默认类型const X int = 10,该Named ConstantTyped Valueconst Y = 10,该Named ConstantUntyped Value
  • 什么是Value Part

    • 一个Value可能会由多个连续的内存块组成,它们被分为Direct PartIndirect Parts
    • 多个Value之间可能会共享Indirect Part,但是Direct Part一定是不共享的。所以Value Size的大小指的就是Direct Part
    • unsafe.Sizeof返回Value Size的大小
  • 哪些类型不支持比较

    • map, slice, functions
    • struct 的 field 类型属于以上三种类型
    • array 的 element 类型属于以上三种类型

指针(Pointers)

  • word的大小?

    • 在32位的操作系统下,word大小为4字节;在64位的操作系统下,word大小为8字节。
  • 什么是Base Type

    • 例如:**int // A non-defined pointer type whose base type is *int.。例如:type PP *Ptr // PP is a defined pointer type whose base type is Ptr.
  • 指针的类型转换规则?

    • 如果这两个类型的底层类型相同(忽略struct tag),则这两个类型之间可以进行显式类型转换。
    • 如果这两个类型中的某一个是Undefined Type(考虑struct tag),那么它们之间可以进行隐式类型转换。
    • 如果两个类型都是Undefined Type,如果它们的Base Type相同,显然它们是相同的类型;否则,如果Base TypeUnderlying Type相同,即可进行显式类型转换。
  • 哪些值是可以取地址的(addressable可写的)?

    • 变量;array的元素;slice的元素;struct的字段
  • 其它值为什么不可以取地址(只读的)?

    • bytes in string: 因为字符串是不可修改的。
    • map element:Go编译器为了采用更高效的算法,将会改变map中元素的地址。
    • dynamic value of interface valuesconstant valuesliteral valuespackage level functionsmethodsintermediate values 等。这些Value是不可被修改的,只能作为赋值表达式的右值。

Structs

  • 什么构成了Struct的标识?

    • field name, field type, field orderfield tag
    • 如果两个Struct Type Literal的这些元素都相同,则这两个Struct Type是相同的。
  • Struct类型转换规则。

    • 如果这两个类型的底层类型相同(忽略struct tag),则这两个类型之间可以进行显式类型转换。
    • 如果这两个类型中的某一个是Undefined Type(考虑struct tag),那么它们之间可以进行隐式类型转换。
  • 如何计算Struct的大小?

    • 某类型的起始地址一定是它的Alignment的整数倍。如果某类型的大小,占四个字节及以下,它的Alignment大小等于Type SizearrayAlignment取决于the type alignment of elementstructAlignment取决于the max type alignment of fields其它类型的alignment值是word
    • 某类型的大小(Type Size)一定是Type Alignment的整数倍。Type Size的大小等于Direct Part的大小。

Value Parts

// map types
type _map *hashtableImpl
// channel types
type _channel *channelImpl
// function types
type _function *functionImpl

type _slice struct {
    // referencing underlying elements
    elements unsafe.Pointer
    // number of elements and capacity
    len, cap int
}

type _string struct {
    elements *byte // referencing underlying bytes
    len      int   // number of bytes
}

type _interface struct {
    dynamicType  *_type         // the dynamic type
    dynamicValue unsafe.Pointer // the dynamic value
}

type _interface struct {
    dynamicTypeInfo *struct {
        dynamicType *_type       // the dynamic type
        methods     []*_function // method table
    }
    dynamicValue unsafe.Pointer // the dynamic value
}

Arrays, Slices and Maps in Go

  • keyelement类型是否有要求?

    • 对于array和slice来说,key必须是int类型;对于map来说key必须是Comparable(== 和 !=),所以slice, map, function不能作为key。
    • element可以是任意类型
  • blank value VS zero value

    • a blank slice: i = []int{},zero value: i = nili = ([]int)(nil)
    • a blank interface: i := map[int]int(nil); a zero-value interface: i = nil
  • Nested Composite Literals Can Be Simplified?

    • 它被限制在使用Value Literal的情况下;
    • 可以不指定element的类型;也可以不指定key的类型。
  • v[k]的注意事项?

    • 如果v是slice类型
      • k值太大或v==nil,都会导致panic
      • 支持v[x:y:z]操作(reslice),要求0 <= x <= y <= z <= cap(v),其中z不是必须的。
    • 如果v是map类型
      • 如果v == nil。如果v[k]作为赋值表达式的左值,会导致panic;如果作为右值,v[k]的值是element的Zero Value
      • 如果k是Interface类型,且dynamic type不支持比较,则产生panic。
  • 如何拷贝一个slice?

    • append是否会为新的slice构建新的Indirect Parts,完全取决于是cap和元素数量的比较。
    • 我们知道y=xy=x[:]操作都会产生一个新的slice。但由于它们共享Indirect Part,x或y的增删改都会影响到对方。
    • 通过y = append(x[:0:0], x)进行一次深度拷贝,使得x和y不再共享Indirect Part
  • Zero Value的进一步解读

    m := *new(map[string]int)   // <=> var m map[string]int
    fmt.Println(m == nil)       // true
    s := *new([]int)            // <=> var s []int
    fmt.Println(s == nil)       // true
    a := *new([5]bool)          // <=> var a [5]bool
    fmt.Println(a == [5]bool{}) // true
    

    所以m==nil,表示m的Direct Part等于0。

  • 修改map元素的注意事项?

    • 你可以通过m[k] = v的方式修改元素的值;
    • 你只能对Direct Part进行整体修改,不能只针对某部分修改,如果元素的类型是struct,m[k].x = 1是不合法的。同理元素类型是array时,也不能对array element进行修改。
  • for...range操作的特殊性?

    • 可以对nil map或nil slice进行遍历
    • 如果删除了未被遍历的元素,则该元素肯定不会被遍历
    • 如果创建了一个新的元素,则该元素可能会被遍历。
  • 删除map中的所有元素?

    for key := range m {
      delete(m, key)
    }
    
  • 删除map中的某个元素?

    for key := range m {
      if key.expired() {
          delete(m, key)
      }
    }
    

Strings

  • 字符串是不可修改的?

    • 字符串是不可被修改的,所以s[i] = 'k'是不合法的。
    • 这带来的好处是字符串的拷贝是高效的,a=b操作只涉及Direct Part部分的修改。注意,a=string(b)操作将会导致字符串的深度拷贝
    • 如果我们尽量使用a=b的模式进行字符串拷贝,字符串之间的比较操作将会很高效。Go只需要检查字符串的长度是否一致,以及Indirect Part对应的内存块的指针是否一致。
  • 字符串和[]byte之间的关系

    • 通过[]byte(str) 和 []rune(str)将字符串类型转换为slice;通过string(xxx)将slice转换成字符串。两者之间的拷贝是深度拷贝
    • 在内置函数appendcopy中,如果第一个参数是[]byte,第二个参数可以是string。
    • 在以下四种情况下,Go编译器会进行优化,防止深度拷贝。
      • a conversion (from string to byte slice) which follows the range keyword in a for-range loop.
      • a conversion (from byte slice to string) which is used as a map key in map element indexing syntax.
      • a conversion (from byte slice to string) which is used in a comparison
      • a conversion (from byte slice to string) which is used in a string concatenation, and at least one of concatenated string values is a non-blank string constant.
  • 字符串的连接操作有哪些?

    • fmt.Sprintfbytes.Bufferstrings.Builderstrings.Join+
  • 关于Unicode和UTF-8之间的关系?

    • Unicode是一个字符集,它为世界上所有的文字进行了编码。但是Unicode的单位是code point,大多数情况下,一个字符对应了一个code point,但是也存在一个字符对应多个code point的情况。
    • Code Point在Go语言中对应了rune类型。UTF-8或者UTF-16是一种对Code Point进行编码的手段。目前,UTF-8最为流行。
    • Go语言要求Go文件是UTF-8编码,string中存储的是UTF-8编码的内容。
    • If a slice rune element value is outside the range of valid Unicode code points, then it will be viewed as 0xFFFD, the code point for the Unicode replacement character. 0xFFFD will be UTF-8 encoded as three bytes (0xef 0xbf 0xbd).
    • Bad UTF-8 encoding representations will be converted to a rune value 0xFFFD. If erroneous UTF-8 is encountered, the character is set to U+FFFD and the index advances by one byte.
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容