golang进阶一:类型比较,常量,nil

2,503 阅读3分钟

1. 类型比较

类型别名

使用类型别名是一个很不错的习惯,可以让代码看起来更易懂友好。例如在源码 builtin.go 中可以看到别名的使用, type byte = uint8 byte 是 uint8 的别名; type rune = int32 rune 是 int32 的别名

// 注意别名的正确声明
type MyInt1 int
type MyInt2 = int

func main() {
    var i int = 0
    var i1 MyInt1 = i // #1
    var i2 MyInt2 = i // #2
    fmt.Println(i1,i2)
}

编译不通过,MyInt1 是一个新类型,MyInt2 是别名,#1 处类型转换将报错。 可修改为类型装换:var i1 MyInt1 = MyInt1(i) // #1

类型比较

go 中不同类型是不能比较的,例如 int 不能和 string 进行比较;false 不能和 0 进行比较。

结构体只能比较是否相等,但是不能比较大小。

type a struct { // 它的变量 可以 == != 比较
    name string
    age  int
}
type b struct { // 它的变量不可以 == != 比较
    age int
    m   map[string]string
}

相同类型的结构体才能够进行比较,结构体是否相同不但与属性类型有关,还与属性顺序相关 如果 struct所有成员都可以比较,则该 struct 就可以通过 ==!= 进行比较是否相等,比较时逐个项进行比较,如果每一项都相等,则两个结构体才相等,否则不相等;

注意,数组类型比较,[2]int [3]int 类型不同,不能进行比较。 切片不能进行比较。

2. 常量

常量寻址

常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。

const i = 100
func main() {
    fmt.Println(&i, i) // &i compile error
}

iota

iota 通常用来声明常量的整数值累加,请牢记:iota 在 const 关键字出现时将被重置为 0,const 中每新增一行常量声明将使 iota 计数一次。

iota 题一

const (
    x = iota
    _
    y
    z = "zz"
    k 
    p = iota
)
const (
    name = "name"
    c    = iota
    d    = iota
)
func main()  {
    fmt.Println(x,y,z,k,p)
    fmt.Println(c,d)
}
// 0 2 zz zz 5
// 1 2

iota 题二

type Direction int
const (
    North Direction = iota
    East
    South
    West
)
func (d Direction) String() string {
    return [...]string{"North", "East", "South", "West"}[d]
}
func main() {
    fmt.Printf("%d %d /n", North, South)
    fmt.Println(South) // Println 会自动使用字符串打印
}

// 0 2
// South

3. 空值与 nil

如果你声明了一个变量但是没有对它进行赋值操作,那么这个变量就会有一个类型的默认零值。

bool      -> false                              
numbers -> 0                                 
string    -> ""      

pointers -> nil
slices -> nil
maps -> nil
channels -> nil
functions -> nil
interfaces -> nil

可见 nil 只能赋值给 指针、chan、func、interface、map 或 slice 类型的变量

var p *int
p == nil    // true
*p          // panic: invalid memory address or nil pointer dereference

指针表示指向内存的地址,如果对为nil的指针进行解引用的话就会导致panic。

nil 题一

type People interface {
    Show()
}

type Student struct{}

func (stu *Student) Show() {}

func main() {
    var s *Student
    if s == nil {
        fmt.Println("s is nil")
    } else {
        fmt.Println("s is not nil")
    }
    var p People = s
    if p == nil {
        fmt.Println("p is nil")
    } else {
        fmt.Println("p is not nil")
    }
}

// s is nil
// p is not nil

当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil

nil 题二

func Foo(x interface{}) {
    if x == nil {
        fmt.Println("empty interface")
        return
    }
    fmt.Println("non-empty interface")
}
func main() {
    var x *int = nil
    Foo(x)
}

// non-empty interface