Golang 入门资料+笔记Golang

第二章 运算

2018-07-11  本文已影响0人  牧码人爱跑马

2.1 运算符

全部运算符及分隔符列表

运算符及分隔符列表.png

优先级

一元运算符优先级最高,二元则分成五个级别,从高向低分别是:


优先级.png

位运算符

位运算符.png

需要注意的是,位清除是go独有的,和位异或是不同的。它将左右操作数对应二进制位都位1的重置为0(有些类似位图),以达到一次清楚多个标记的目的。

package main

import "fmt"

const (
    exec   byte = 1 << iota
    write
    read
    freeze
)

func main() {
    a := read | write | freeze
    b := read | freeze | exec
    c := a &^ b //相当于a ^ read ^ freeze, 但不包括exec
    fmt.Printf("%04b &^ %04b = %04b\n", a, b, c)

}

输出:

1110 &^ 1101 = 0010

自增

自增自减不再是运算符,只能作为独立语句,不能用于表达式。
另,go中没有形如++a这种。

指针

内存地址和指针是不同的。

内存地址是内存中每个字节单元的唯一编号,而指针则是一个实体。 指针会分配内存空间,相当于一个专门用来保存地址的整型变量。

内存地址和指针.png

并非所有对象都能进行取地址操作,但变量总是能正确返回。指针运算符为左值时,我们可更新目标对象状态;而为右值时则是为了获取目标状态。

package main

func main() {
    x := 10
    var p *int = &x  //获取地址,保存到指针变量
    *p += 20    //用指针间接引用,并更新对象
    println(&p,p, *p)   //输出指针本身的地址,所存储的地址,以及目标对象
}

输出:

0xc04202ff68 0xc04202ff58 30

    m:=map[string]int{"a":2}
    println(&m["a"])     //报错:不能取地址

指针类型支持相等运算符,但不能作加减法和类型转换。如果两个指针指向同一地址或都为nil,那么他们相等。

   x:=10
   p:=&x
   println(*p) //10
   *p++
   //var p2 *int = *p + 2  //报错,*int和int不能相加
   println(*p)  //11
   p3 := &x
   println(p == p3)

可通过unsafe.Pointer将指针转换为uintpr后进行加减法运算,但可能会造成非法访问。

Pinter 类似C中的void*万能指针,可用来转换指针类型。它能安全持有对象或对象成员,但uintptr不行。后者仅是一种特殊整型,并不引用目标对象,无法阻止垃圾回收器回收对象内存。

指针没有专门指向成员的“->”运算符,统一使用“.”选择表达式。

package main

func main() {
    var a struct{
        x int
    }
    //a:= struct {
    //  x int
    //}{}         //同上,不同写法
    a.x = 100
    p := &a
    p.x += 100
    println(p.x)
}

零长度对象的地址是否相等和具体的实现版本有关,不过肯定不等于nil。

package main

func main() {
    var a,b struct{}
    println(&a,&b)
    println(&a == &b,&a == nil)
}

输出:

0xc04202ff70 0xc04202ff70
false false

即便长度为0,可该对象依然是“合法存在”的,拥有合法内存地址,这与nil语义完全不同。
在runtime/malloc.go里有个zerobase全局变量,所有通过mallocgc分配的零长度对象都使用该地址。不过上栗中,对象a,b在栈上分配,并未调用mallocgc函数。

上一篇下一篇

猜你喜欢

热点阅读