Go学习笔记-第1章

来源:互联网 发布:机顶盒检测软件 编辑:程序博客网 时间:2024/06/03 14:41

Go 学习笔记

第一章 类型

1.1 变量

Go 语言变量名由字母、数字、下划线组成,其中首个字母不能为数字。
Go 是静态类型语⾔,不能在运⾏期改变变量类型。
使⽤关键字 var 定义变量,⾃动初始化为零值。如果提供初始化值,可省略变量类型,由编译器⾃动推断。

var x int var y int  = 1var radius float32 = 2.0var str = "Hello Go"

在函数内部,可⽤更简略的 “:=” ⽅式定义变量。

var func main(){    m:="abc"} 

可以一次定义多个变量。

var x,y,z int //定义全局变量var m,n = "abc",123  var (    a int    b float32)var func main(){    i := "Hello Go" //编译器会将未使⽤的局部变量当做错误=>i declared and not used。    println(x, n, b)} 

注意重新赋值与定义新同名变量的区别。

var (    a int    b float32)func main() {    println(&a)    m := "Hello Go"    println(&m)    m, n := "what?", 10 // 重新赋值: 与前 m 在同 层次的代码块中,且有新的变量被定义。    println(&m, n)    a := 12 // 定义新同名变量: 不在同层次代码块。    println(&a)}  

输出结果

0x10b29a80xc420039f680xc420039f68 100xc420039f60

1.2 常量

常量值必须是编译期可确定的数字、字符串、布尔值。

const x, y, z = 1, "Hello Go", false //多常量初始化const ( //常量组    m    = false    n    = false    i, j = "abc", 1 //类型自动判断)func main() {    const x = 2//未使用局部常量不会引发编译错误}

在常量组中,如不提供类型和初始化值,那么视作与上 常量相同。

const ( //常量组    m = false    n   //n = false    i = 10    j   //j = 10)

常量值还可以是 len、cap、unsafe.Sizeof 等编译期可确定结果的函数返回值。

const (    x = "Hello Go"    y = len(x)    z = unsafe.Sizeof(x))

如果常量类型 以存储初始化值,那么不会引发溢出错误。

const (    x byte = 20    y int  = 1e20//constant 100000000000000000000 overflows int)

枚举
关键字 iota 定义常量组中从 0 开始按 计数的 增枚举值。

const (    Sunday = iota //0    Monday        //1    Tuesday       //2    Wednesday     //3    Thursday      //4    Friday        //5    Saturday      //6)
const (    _        = iota             // iota = 0    KB int64 = 1 << (10 * iota) // iota = 1    MB                          // 与 KB 表达式相同,但 iota = 2  等同于=> MB int64 = 1 << (10 * 2)    GB    TB)

在同 常量组中,可以提供多个 iota,它们各增 。

const (    A, B = iota, iota << 10 //0,0 << 10)

如果 iota 增被打断,须显式恢复。

const (    A = iota //1    B        //2    C = "c"  //c    D        //c    E = iota //4 显式恢复。注意计数包含了 C、D 两行 。    F        //5    G        //6)

1.3 基本类型

支持八进制、 十六进制,以及科学记数法。标准库 math 定义了各数字类型取值范围。

a, b, c, d := 071, 0x1F, 1e9, math.MinInt16

空指针值 nil

1.4 引用类型

引 类型包括 slice、map 和 channel。它们有复杂的内部结构,除了申请内存外,还需
要初始化相关属性。
内置函数 new 计算类型 ,为其分配零值内存,返回指针。 make 会被编译器翻译 成具体的创建函数,由其分配内存和初始化成员结构,返回对象 指针。

number := []int{0, 0, 0}number[1] = 10x := make([]int, 3) // len = 3  slice.c: runtime·makeslicex[1] = 10y := new([]int)y[0] = 10 // Error: invalid operation: y[1] (index of type *[]int)

1.5 类型转换

不⽀持隐式类型转换,即便是从窄向宽转换也不⾏。

var x byte = 10//var m int = x //cannot use x (type byte) as type int in assignmenty := int(x)

同样不能将其他类型当 bool 值使⽤。

var x  = 1if x {//non-bool x (type int) used as if condition    println("true")}

1.6 字符串

字符串是不可变值类型,内部⽤指针指向 UTF-8 字节数组。
• 默认值是空字符串 “”。
• ⽤索引号访问某字节,如 s[i]。
• 不能⽤序号获取字节元素指针,&s[i] ⾮法。
• 不可变类型,⽆法修改字节数组。
• 字节数组尾部不包含 NULL。

// string is the set of all strings of 8-bit bytes, conventionally but not// necessarily representing UTF-8-encoded text. A string may be empty, but// not nil. Values of string type are immutable.type string string

使⽤索引号访问字符 (byte)。

var str = "Hello Goland"println(str[0] == 72, str[1], str[len(str)-1])

输出

true 101 100

连接跨⾏字符串时,”+” 必须在上⼀⾏末尾,否则导致编译错误。

var str = "Hello " + " Goland"s2 := "Hello, "    + "World!" //invalid operation: + untyped stringprintln(str)println(s2)

⽀持⽤两个索引号返回⼦串。⼦串依然指向原字节数组,仅修改了指针和⻓度属性。

str := "Hello " + " Goland"str1 := str[1:]  //ello  Golandstr2 := str[:6]  //Hello str3 := str[2:5] //lloprintln(str1)println(str2)println(str3)

单引号字符常量表⽰ Unicode Code Point,⽀持 \uFFFF、\U7FFFFFFF、\xFF 格式。
对应 rune(int32) 类型,UCS-4。

func main() {    fmt.Printf("%T\n", 'a')    var c1, c2 rune = '\u6211', '们'    println(c1 == '我', string(c2) == "\xe4\xbb\xac")}

输出

int32true true

要修改字符串,可先将其转换成 []rune 或 []byte,完成后再转换为 string。⽆论哪种转
换,都会重新分配内存,并复制字节数组。

str := "Hello Goland"number := "110"s := []byte(str)phone := []rune(number)s[0] = 'F'phone[len(number)-1] = '9'println(string(s))println(string(phone))

输出

Fello Goland119

⽤ for 循环遍历字符串时,也有 byte 和 rune 两种⽅式。

str := "Hello"for i := 0; i < len(str); i++ { //byte    fmt.Printf("str[%d] = %c \n", i, str[i])}for _, value := range str {     //rune    fmt.Printf("%c\n", value)}

输出

str[0] = H str[1] = e str[2] = l str[3] = l str[4] = o Hello

1.7 指针

⽀持指针类型 T,指针的指针 **T,以及包含包名前缀的 \

type User struct {    name string}user := User{"小强"}userIp := &uservar ipStr *UseripStr = &userprintln(ipStr)println(userIp)fmt.Printf("name=%s\n", userIp.name) 

输出

0xc420039f58name=小强0xc420039f58

不能对指针做加减法等运算。

number := 1234p := &numberp++ //invalid operation: p++ (non-numeric type *int)

可以在 unsafe.Pointer 和任意类型指针间进⾏转换。

x := 0x12345678p := unsafe.Pointer(&x) // *int -> Pointern := (*[4]byte)(p)      // Pointer -> *[4]bytefor i := 0; i < len(n); i++ {    fmt.Printf("%X ", n[i])}

输出

78 56 34 12 0xc420039f48

返回局部变量指针是安全的,编译器会根据需要将其分配在 GC Heap 上。

func test() *int { x := 100 return &x // 在堆上分配 x 内存。但在内联时,也可能直接分配在目标栈。}

将 Pointer 转换成 uintptr,可变相实现指针运算。

func main() {    d := struct {        s string        x int    }{"abc", 100}    p := uintptr(unsafe.Pointer(&d)) // *struct -> Pointer -> uintptr    p += unsafe.Offsetof(d.x)        // uintptr + offset    p2 := unsafe.Pointer(p)          // uintptr -> Pointer    px := (*int)(p2)                 // Pointer -> *int    *px = 200                        // d.x = 200    fmt.Printf("%#v\n", d)}

输出

struct { s string; x int }{s:"abc", x:200}

注意:GC 把 uintptr 当成普通整数对象,它⽆法阻⽌ “关联” 对象被回收。

原创粉丝点击