zoukankan      html  css  js  c++  java
  • Go 中的可寻址和不可寻址怎么理解?

    大家好,我是明哥。

    欢迎大家再次来到  『Go 语言面试题库』 这个专栏

    本专栏内容,已经上传 github:https://github.com/iswbm/golang-interview

    请大家帮帮忙去点个小 ⭐⭐,在那里我对题库进行了分类整理。

    本篇问题:Go 中的可寻址和不可寻址怎么理解?

    # 1. 什么叫可寻址?

    可直接使用 & 操作符取地址的对象,就是可寻址的(Addressable)。比如下面这个例子

    func main() {
        name := "iswbm"
        fmt.Println(&name) 
        // output: 0xc000010200
    }

    程序运行不会报错,说明 name 这个变量是可寻址的。

    但不能说 "iswbm" 这个字符串是可寻址的。

    "iswbm"  是字符串,字符串都是不可变的,是不可寻址的,后面会介绍到。

    在开始逐个介绍之前,先说一下结论

    • 指针可以寻址:&Profile{}

    • 变量可以寻址:name := Profile{}

    • 字面量通通不能寻址:Profile{}

    # 2. 哪些是可以寻址的?

     变量:&x

    func main() {
        name := "iswbm"
        fmt.Println(&name) 
        // output: 0xc000010200
    }

     指针:&*x

    type Profile struct {
        Name string
    }

    func main() {
        fmt.Println(unsafe.Pointer(&Profile{Name: "iswbm"}))
        // output: 0xc000108040
    }

     数组元素索引: &a[0]

    func main() {
        s := [...]int{1,2,3}
        fmt.Println(&s[0])
        // output: xc0000b4010
    }

     切片

    func main() {
        fmt.Println([]int{1, 2, 3}[1:])
    }

     切片元素索引:&s[1]

    func main() {
        s := make([]int , 2, 2)
        fmt.Println(&s[0]) 
        // output: xc0000b4010
    }

     组合字面量: &struct{X type}{value}

    所有的组合字面量都是不可寻址的,就像下面这样子

    type Profile struct {
        Name string
    }

    func new() Profile {
        return Profile{Name: "iswbm"}
    }

    func main() {
        fmt.Println(&new())
        // cannot take the address of new()
    }

    注意上面写法与这个写法的区别,下面这个写法代表不同意思,其中的 & 并不是取地址的操作,而代表实例化一个结构体的指针。

    type Profile struct {
        Name string
    }

    func main() {
        fmt.Println(&Profile{Name: "iswbm"}) // ok
    }

    虽然组合字面量是不可寻址的,但却可以对组合字面量的字段属性进行寻址(直接访问)

    type Profile struct {
        Name string
    }

    func new() Profile {
        return Profile{Name: "iswbm"}
    }

    func main() {
        fmt.Println(new().Name)
    }

    # 3. 哪些是不可以寻址的?

     常量

    import "fmt"

    const VERSION  = "1.0"

    func main() {
        fmt.Println(&VERSION)
    }

     字符串

    func getStr() string {
        return "iswbm"
    }
    func main() {
        fmt.Println(&getStr())
        // cannot take the address of getStr()
    }

     函数或方法

    func getStr() string {
        return "iswbm"
    }
    func main() {
        fmt.Println(&getStr)
        // cannot take the address of getStr
    }

     基本类型字面量

    字面量分:基本类型字面量 和 复合型字面量

    基本类型字面量,是一个值的文本表示,都是不应该也是不可以被寻址的。

    func getInt() int {
        return 1024
    }

    func main() {
        fmt.Println(&getInt())
        // cannot take the address of getInt()
    }

     map 中的元素

    字典比较特殊,可以从两个角度来反向推导,假设字典的元素是可寻址的,会出现 什么问题?

    1. 如果字典的元素不存在,则返回零值,而零值是不可变对象,如果能寻址问题就大了。

    2. 而如果字典的元素存在,考虑到 Go 中 map 实现中元素的地址是变化的,这意味着寻址的结果也是无意义的。

    基于这两点,Map 中的元素不可寻址,符合常理。

    func main() {
        p := map[string]string {
            "name": "iswbm",
        }

        fmt.Println(&p["name"])
        // cannot take the address of p["name"]
    }

    搞懂了这点,你应该能够理解下面这段代码为什么会报错啦~

    package main

    import "fmt"

    type Person struct {
        Name  string
        Email string
    }

    func main() {
        m := map[int]Person{
            1:Person{"Andy", "1137291867@qq.com"},
            2:Person{"Tiny", "qishuai231@gmail.com"},
            3:Person{"Jack", "qs_edu2009@163.com"},
        }

        //编译错误:cannot assign to struct field m[1].Name in map
        m[1].Name = "Scrapup"

     数组字面量

    数组字面量是不可寻址的,当你对数组字面量进行切片操作,其实就是寻找内部元素的地址,下面这段代码是会报错的

    func main() {
        fmt.Println([3]int{1, 2, 3}[1:])
        // invalid operation [3]int literal[1:] (slice of unaddressable value)
    }
  • 相关阅读:
    67. Add Binary
    66. Plus One
    64. Minimum Path Sum
    63. Unique Paths II
    How to skip all the wizard pages and go directly to the installation process?
    Inno Setup打包之先卸载再安装
    How to change the header background color of a QTableView
    Openstack object list 一次最多有一万个 object
    Openstack 的 Log 在 /var/log/syslog 里 【Ubuntu】
    Git 分支
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/15423910.html
Copyright © 2011-2022 走看看