Go学习笔记-第1章

Go 学习笔记

第一章 类型

1.1 变量

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

var x int 
var y int  = 1
var radius float32 = 2.0
var 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)
}  

输出结果

0x10b29a8
0xc420039f68
0xc420039f68 10
0xc420039f60
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] = 10

x := make([]int, 3) // len = 3  slice.c: runtime·makeslice
x[1] = 10

y := 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 assignment
y := int(x)

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

var x  = 1
if 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 string

println(str)
println(s2)

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

str := "Hello " + " Goland"

str1 := str[1:]  //ello  Goland
str2 := str[:6]  //Hello 
str3 := str[2:5] //llo

println(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")
}

输出

int32
true 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 Goland
119

⽤ 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 
H
e
l
l
o
1.7 指针

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

type User struct {
    name string
}

user := User{"小强"}
userIp := &user

var ipStr *User
ipStr = &user

println(ipStr)
println(userIp)
fmt.Printf("name=%s\n", userIp.name) 

输出

0xc420039f58
name=小强
0xc420039f58

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

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

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

x := 0x12345678
p := unsafe.Pointer(&x) // *int -> Pointer
n := (*[4]byte)(p)      // Pointer -> *[4]byte
for 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 当成普通整数对象,它⽆法阻⽌ “关联” 对象被回收。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值