GO 学习笔记(二)

发表信息: by

  • 文章标签:
  • go 2

1 语言

1.1 类型

1.1.1 变量

  • Go 是静态类型语 ,不能在运 期改变变量类型。
  • var 定义变量,自动初始化为零值, 如果手动提供初始化,可以省略类型
  • 在函数内部用 := 定义变量更加方便
  • 未使用的局部变量将会报错
  • 统一代码块内对同名变量重新定义等于重新赋值,不同代码块对同名变量重新定义等于新建
  • := 必须产生新变量
package main

import (
    "fmt"
)

func main() {
    var a int
    var b float32 = 2.1
    var c = "hello"
    d := 3
    var e, f, g int = 1, 2, 3
    var (
        h int = 1
        i = 2.0
    )
    j, k := "world", 3
    _, l := 1, 2

    fmt.Println(a, b, c, d, e, f, g, h, i, j, k)
    _ = l

    m := 1
    fmt.Println(&m, m) //0xc420070208, 1
    m, n := 2, 3
    // m := 4 不允许,因为:=没有产生新的变量
    _ = n
    fmt.Println(&m, m) //0xc420070208, 2

    {
        m := 3
        fmt.Println(&m, m) //0xc420070220, 3
    }
}

1.1.2 常量

  • 常量值必须是编译期可确定的数字、字符串、布尔值。
  • 不支持持 1UL、2LL 这样的类型后缀。
  • 在常量组中,不提供初始值,则默认与上一个值相同
  • 常量值可以是在编译器能确定内容的函数
package main

import (
    "fmt"
)

const (
    a = 1
    b = true
    c = "hello"
    d = len(c)
    e
)

func main() {
    fmt.Println(a, b, c, d, e) //1 true hello 5 5
}

1.1.3 枚举

package main

import (
    "fmt"
)

type Color int //自定义类型

const (
    // iota 自增值
    Sunday = iota
    Monday
    Tuesday
    Wednesday
)

const (
    _ = iota
    KB = 1 << (10 * iota)
    MB = 1 << (10 * iota)
)

const (
    A, B = iota, 10*iota
    C, D
)

const (
    Red Color = iota
    Blue
)

var a = 2 //未使用的全局变量不会出错

func test (c Color) {}

func main() {
    fmt.Println(Sunday, Monday, Tuesday) //0 1 2
    fmt.Println(KB, MB, A, B, C, D) //1024 1048576 0 0 1 10
    fmt.Println(Red, Blue) //0 1

    c1 := Red
    c2 := 1

    test(c1)
//    test(c2) // 出错, int 与 Color 不是一个类型
    _ = c2
    test(1) // 自动转换成Red
}

1.1.4 基本类型

  • 空指针nil,不是NULL
  • 值类型 bool, byte, rune, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64, complex64, complext128, uintptr, array, struct, string
  • 引用类型 slice, map, channel, interface, function
  • new([]int) 计算类型大小,分配零值,返回指针; make([]int) 分配内存,创建数据结构,返回对象
  • 不支持隐式类型转换
  • 不可以用其他值代表bool
  • 字符串 可以 s[i] 访问内部元素, 不可以对内部元素进行赋值s[i] = 1, 不可以访问内部元素的指针 &s[i], 支持` 和" 两种定义形式, 链接跨行字符串+必须放在上一行末尾,修改字符串肯定会重新分配内存,

侵删

1.1.5 指针类型

  • 默认nil,没有NULL常量
  • 操作符 & 取变量地址,* 操作符通过指针访问目标对象
  • 不支持指针运算,不支持 -> 操作符, 可以直接. 访问对象

1.1.6 自定义类型

可以将类型分为命名类型和未命名类型, 命名类型包括bool, int, string, 等, 未命名类型包括array, map, slice等

具有相同声明的未命名类型被视为同一类:

  • 具有相同基本类型的指针
  • 具有相同元素和长度的array
  • 具有相同key-value的map
  • 具有相同元素类型的slice
  • 具有相同元素类型和方向的channel
  • 具有相同字段序列的匿名struct
  • 签名相同的fuction(不包括参数名)
  • 方法集相同的interface

type关键字可以在局部或者全局定义类型,新定义的类型并不是被定义类型的别名, 除非目标是非命名类型,否则必须显示转换

type bigint int64

var a bigint = 2
var b int64 = 3

a = bigint(b)

1.2 表达式

1.2.1 运算符

  • ++ -- 是语句而非表达式
  • 没有~, 可以用^ 取反

1.2.2 初始化

  • 初始化复合对象,必须使用类型标签,且做大括号必须在类型的尾部 var a = []int {1,2,3} `var a = struct { v1 int } {10}
  • 初始化值可以用,分割,但是最后一行必须以,或者}结尾
var a = []int {
                1,
                2,
                3,
              }

var b = []int {
                1,
                2,
                3}

1.2.3 控制流

if

  • 可以省略条件表达式的括号
  • 支持初始化语句,可定义局部变量
  • { 必须放在条件表达式右面
  • 不支持三元操作符

for

for i := 0; i < 100; i++ {
    // do
}

i := 0
for i < 10 {
    // do
    i++
}

for {
    //dp
}

range

迭代操作,返回 (索引,值) 或 (键,值)

  • range 会复制 对象的值
package main

import (
    "fmt"
)

func main() {
    a := []int {1,2,3,4}
    fmt.Println(a[1], &a[1])

    for i, v :=  range a {
        fmt.Println(v, &v, &a[i])
    }
}

/*
1 0xc42000e140 0xc42000a2a0
2 0xc42000e140 0xc42000a2a8
3 0xc42000e140 0xc42000a2b0
4 0xc42000e140 0xc42000a2b8
*/

switch

x := []int{1, 2, 3}
i := 2
switch i {
    case x[1]:
        println("a")
    case 1, 3:
        println("b")
        break
    default:
        println("c")
}

// a 为什么呢? 因为只会运行一个case,默认省略了break

goto break continue

package main

import (
    "fmt"
)

func main(){
FOR1:
    for i := 0; i < 100; i++ {
FOR2:
        for j := 0; j < 100; j++ {
            fmt.Println(i,j)
            if i == 10 {
                break FOR2
            }
            if i == 20 {
                continue FOR1
            }
            if i == 30 {
                goto EXIT
            }
        }
    }

    EXIT:
        fmt.Println("exit")
}

1.3 函数

1.3.1 函数定义

  • 不支持重载,默认参数,嵌套
  • 支持不定长参数,支持多返回,支持命名返回参数,支持匿名和闭包
  • { 依旧不能另起一行

1.3.2 可变参数

  • 可变参数本质是slice, 只能有一个且只能为最后一个
  • 使用slice对象做变参的时候,必须展开
  • defer 延迟调用
package main

import (
    "fmt"
)

type MyFunc func(int, string) int

func test1 (mf MyFunc, a int, b string) (c int){
    c = mf(a, b)
    return
}

func test2 (mf func(int) int, a int) int {
    return mf(a)
}

func main(){
    a := func(a int, b string) int {
        return a + len(b)
    }

    fmt.Println(test1(a, 1, "hello"))

    fmt.Println(test2(func(a int) int { a++ ; return a}, 1))
}
func test(s string, n ...int) string {
    var x int
    for _, i := range n {
        x += i
}
    return fmt.Sprintf(s, x)
}
func main() {
    s := []int{1, 2, 3}
    println(test("sum: %d", s...))
}