zoukankan      html  css  js  c++  java
  • golang(二)

    基本结构和基本数据类型

    指针

    不像 Java 和 .NET,Go 语言为程序员提供了控制数据结构的指针的能力;但是,你不能进行指针运算。
    通过给予程序员基本内存布局,Go 语言允许你控制特定集合的数据结构、分配的数量以及内存访问模
    式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是
    系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。


    由于各种原因,指针对于使用面向对象编程的现代程序员来说可能显得有些陌生,不过我们将会在这一小
    节对此进行解释,并在未来的章节中展开深入讨论。


    程序在内存中存储它的值,每个内存块(或字)有一个地址,通常用十六进制数表示,如: 0x6b0820 或
    0xf84001d7f0 。


    Go 语言的取地址符是 & ,放到一个变量前使用就会返回相应变量的内存地址。
    下面的代码片段(示例 4.9 pointer.go)可能输出 An integer: 5, its location in memory: 0x6b0820
    (这个值随着你每次运行程序而变化)。

    var i1 = 5
    fmt.Printf("An integer: %d, it's location in memory: %p
    ", i1, &i1)

     

    这个地址可以存储在一个叫做指针的特殊数据类型中,在本例中这是一个指向 int 的指针,即 i1 :此处
    使用 *int 表示。如果我们想调用指针 intP,我们可以这样声明它:


    var intP *int

    然后使用 intP = &i1 是合法的,此时 intP 指向 i1。(指针的格式化标识符为 %p )intP 存储了 i1 的内存地址;

    它指向了 i1 的位置,它引用了变量 i1。一个指针变量可以指向任何一个值的内存地址 它指向那个值的内存地址,

    在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,

    可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上 * 号(前缀)

    来获取指针所指向的内容,这里的* 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。

    当一个指针被定义后没有分配到任何变量时,它的值为 nil 。一个指针变量通常缩写为 ptr 。

    注意事项
    在书写表达式类似 var p *type 时,切记在 * 号和指针名称间留有一个空格,因为 - var p*type 是
    语法正确的,但是在更复杂的表达式中,它容易被误认为是一个乘法表达式!
    注意:

    符号 * 可以放在一个指针前,如 *intP ,那么它将得到这个指针指向地址上所存储的值;这被称为反引用
    (或者内容或者间接引用)操作符;另一种说法是指针转移。
    对于任何一个变量 var, 如下表达式都是正确的: var == *(&var) 。

    现在,我们应当能理解 pointer.go 中的整个程序和他的输出:


    示例 pointer.go:

    package main
    import "fmt"
    func main() {
        var i1 = 5
        fmt.Printf("An integer: %d, its location in memory: %p
    ", i1, &i1)
        var intP *int
        intP = &i1
        fmt.Printf("The value at memory location %p is %d
    ", intP, *intP)
    }
    pointer.go

        输出:

     

     程序 string_pointer.go 为我们展示了指针对string的例子。
    它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)。

     

      示例  string_pointer.go

    package main
    import "fmt"
    func main() {
        s := "good bye"
        var p *string = &s
        *p = "ciao"
        fmt.Printf("Here is the pointer p: %p
    ", p) // prints address
        fmt.Printf("Here is the string *p: %s
    ", *p) // prints string
        fmt.Printf("Here is the string s: %s
    ", s) // prints same string
    }
    string_pointer.go

         输出:

     通过对 *p 赋另一个值来更改“对象”,这样 s 也会随之更改 。

    注意事项
    你不能得到一个文字或常量的地址,例如

     注意事项
    你不能得到一个文字或常量的地址,例如 :

    const i = 5
    ptr := &i //error: cannot take the address of i
    ptr2 := &10 //error: cannot take the address of 10

    所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导
    致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如: pointer+2 ,移动指针指向字符串
    的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和VB.NET 中的引用。
    因此 c = *p++ 在 Go 语言的代码中是不合法的。

    指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传
    递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都
    有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,
    所以从它们被创建开始就具有相互独立的生命周期。


    另一方面(虽然不太可能),由于一个指针导致的间接引用(一个进程执行了另一个地址),指针的过度
    频繁使用也会导致性能下降。


    指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数
    情况这会使你的代码结构不清晰。


    如我们所见,在大多数情况下 Go 语言可以使程序员轻松创建指针,并且隐藏间接引用,如:自动反向引用。
    对一个空指针的反向引用是不合法的,并且会使程序崩溃:

      示例 testcrash.go:

    package main
    func main() {
    var p *int = nil
    *p = 0
    }//
    in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
    // runtime error: invalid memory address or nil pointer dereference
    testcrash.go
  • 相关阅读:
    20210718力扣第249场周赛(五)
    统计学习方法第三章 k近邻法
    统计学习方法第二章
    启发式搜索
    洛谷P2015 二叉苹果树
    Codeforces Round #736 (Div. 2). D
    牛客多校第五场 K King of Range
    RMQ/ST表
    AcWing100 IncDec Sequence
    AcWing 368. 银河
  • 原文地址:https://www.cnblogs.com/zeroLJ/p/11794388.html
Copyright © 2011-2022 走看看