zoukankan      html  css  js  c++  java
  • Go基础--笔记

    Go语言基础部分学习笔记:

    (系统不支持插入Go代码 下面插入的代码选用的格式是C++......)

    以下内容更多的并非解释相关知识是什么意思,而是给有过其他语言基础的人看看Go语言的语法格式,如何快速使用Go

    代码可以去Github下载:wangmlshadow/notebook-Go: Go语言学习 (github.com)

    首先是学任何一个语言都会首先去做的事,HelloWorld:

    package main
    
    import "fmt"
    
    // 行注释
    /*
    块注释
    */
    // 快速注释 ctrl + /
    
    func main() {
        // print
        fmt.Println("Hello World")
    }

    变量部分:

    和大部分语言一样,Go支持整形、浮点型、布尔类型、字符串类型,不过需要注意的是Go定义变量的方式

    // 定义
    // 格式:var 变量名 变量类型
    var a int = 10
    var b int
    b = a// 赋值
    // 自动推导变量类型
    PI := 3.1415
    // 声明多个变量并赋值
    c, d := 1, 2

    字符和字符串:

    package main
    
    import "fmt"
    
    func main() {
       var a byte = 'a'
       var b string = "a"
       fmt.Println(a, b)
    
       str := "123456789"
       // len() 系统函数 计算字符串长度
       length := len(str)
       fmt.Println(length)
    
       str1 := "哈哈哈哈"
       fmt.Println(len(str1))// 在Go中一个汉字等于3个字符 为了和Linux进行统一处理
    }

    常量的使用:

        // 常量存储在数据区 变量存储在栈中
        const a int = 10
        fmt.Println(a)

    怎么用输入输出:

    可以看一下包fmt的文档,这里仅仅放一个例子

    // 格式输入
    var a int
    // & 取地址
    fmt.Scan(&a)
    // %p 占位符 表示输出一个数据对应的内存地址
    fmt.Printf("%p", &a)

    运算符:

    和大部分语言一样,包括算术运算符、关系运算符、逻辑运算符

        // + - * / %
        // ++ -- 自增 自减只有放在变量后面的形式 没有放在前面的
        a := 10
        a++
        fmt.Println(a)
        a--
        fmt.Println(a)
        b := 3
        c := a / b//整型相除仍然是整型
        fmt.Println(c)
        // 赋值运算符
        //  = += -= /= *=
        // 逻辑运算符
        // ! && ||
        // 关系运算符
        // > < == != >= <=  

    流程控制:

    包括if else、switch、循环只有for

    func main() {
        // 选择
        // 注意格式 可嵌套
        age := 17
        if age < 18 {
            fmt.Println("未成年")
        } else if age >= 18 && age < 35 {// 注意 此处要写在同一行
            fmt.Println("青年")
        } else {// 注意 此处要写在同一行
            fmt.Println("成年")
        }
    
        // switch
        // 通过值进行选择
        // switch中不能用浮点型数据 浮点型数据是一个约等于的数据
        var w int
        fmt.Scan(&w)
        switch w {
        case 1:
            fmt.Println("星期一")
            fallthrough// 让switch执行下一个分支的代码 如果不写执行到下一个分支就会自动停止 这个程序会在输入 1 的时候会输出 星期一 星期二
        case 2:
            fmt.Println("星期二")
        case 3:
            fmt.Println("星期三")
        case 4:
            fmt.Println("星期四")
        case 5:
            fmt.Println("星期五")
        case 6:
            fmt.Println("星期六")
        case 7:
            fmt.Println("星期日")
        default:
            fmt.Println("error")
        }
    
        // 循环结构
        // go语言中只有一种循环结构 for循环
        var i int
        for i = 1; i < 10; i++ {
            fmt.Println(i)
        }
        
        for j := 1; j < 10; j++ {
            fmt.Println(j)
        }
        
        for j := 1; j < 10; j++ {
             if j == 1 {
                 continue
             }
            fmt.Println(j)
        }
    
        for ; ; {// 死循环
            break// 跳出
        }
        for{// 死循环另一种写法
            break// 跳出
        }
    }

    函数的定义与使用:

    函数中变量的作用域、传参等就不做介绍

    package main
    
    import "fmt"
    
    func test()  {
        fmt.Println("asdasd")
    }
    
    func test2(a int, b int)  {
        fmt.Println(a + b)
    }
    
    func test3(a int, b int) (sum int) {
        sum = a + b
        return
    }
    // type 可以定义函数类型
    // type 可以为已存在的类型起别名
    type FUNCTYPE func()
    type FUNCTEST func(int, int)
    type FUNCDEM func(int, int)int
    
    func main() {
        // 定义函数类型变量
        var f FUNCTYPE
        f = test
        // 通过函数变量调用函数
        f()
    
        var f1 FUNCTEST
        f1 = test2
        f1(1, 2)
    
        var f2 FUNCDEM
        f2 = test3
        _ = f2(1, 2)
    }

    匿名函数:

    package main
    
    import "fmt"
    
    func main() {
        a, b := 1, 2
        // 匿名函数
        // 定义并调用
        //func (a int, b int) {
        //    fmt.Println(a + b)
        //}(a, b)
        f := func (a int, b int) {
            fmt.Println(a + b)
        }
        f(a, b)
    
        f1 := func (a int, b int) int {
            return a + b
        }(a, b)
        fmt.Println(f1)
    }

    切片(或者说数组)的使用:

    注意不要以为和Python的切片是一个意思,Go中的切片截取可以看作Python中的数组切片

    package main
    
    import "fmt"
    
    // 切片作为函数参数
    func test(s []int) {
        s[0] = 88// 切片传递地址 源切片数据也会被改变
        fmt.Println(s)
    }
    
    func main() {
        // 数组定义 var 数组名 [元素个数]数据类型
        // 切片定义 var 切片名 []数据类型
    
        //var s []int
        //fmt.Println(s)
    
        // 自动推导类型创建切片
        s := make([]int, 5)// 设置长度为5
        s[0] = 1
        s[1] = 2
    
        //s[6] = 7// error 越界
        // 使用append添加元素
        fmt.Println(len(s))
        s = append(s, 6, 7 , 8, 9)
        fmt.Println(len(s))
        fmt.Println(s)
        // 查看容量
        fmt.Println(cap(s))
    
        // go的切片不是python的切片 可以看作C++的vector
    
        // 推荐使用切片而不是数组
    
        // 切片的截取 类似于python的切片
        fmt.Println(s[2:])
        fmt.Println(s[:4])
        fmt.Println(s[2:4])
        fmt.Println(s[0:2:4])// low = 0 height = 2 max = 4 cap = max - low
    
        slice := s[2:4]// 切片数据仍然指向原始的s 修改slice的话s也会被修改
        slice[0] = 9
        slice[1] = 9
        fmt.Println(slice)
        fmt.Println(s)
    
        s2 := make([]int, len(s))
        copy(s2, s)// 拷贝操作 深拷贝 s2需要有足够的空间存放拷贝过来的数据
        s2[0] = 100
        fmt.Println(s)
        fmt.Println(s2)
        // 也可因copy切片的截取部分
    
        test(s)
        fmt.Println(s)
    }

    map的使用:

    package main
    
    import "fmt"
    
    // map作为函数参数 是地址传递
    func  test(m map[int]string)  {
        m[1] = "AAAAAA"
    }
    
    func main() {
        // map key 必须是基本数据类型
       //var m map[int]string
       m := make(map[int]string, 1)// map自动扩容
       fmt.Println(m)
       m[1] = "asdasd"
       m[2] = "safasd"
       m[9] = "asfkasd"
       fmt.Println(m)
       fmt.Println(m[2])
    
       for k, v := range m {
           fmt.Println(k, v)
        }
    
        // 判断是否存在key
        v1, ok1 := m[1]
        v5, ok5 := m[5]
    
        if ok1 {
            fmt.Println(v1)
        } else {
            fmt.Println("key 1 not existed")
        }
    
        if ok5 {
            fmt.Println(v5)
        } else {
            fmt.Println("key 5 not existed")
        }
    
        // 删除map中的元素
    
        fmt.Println(m)
        delete(m, 1)
        // delete删除map元素时 表示的时若可key存在就删除 不存在也不会报错
        delete(m, 5)
        fmt.Println(m)
    
        test(m)
    
        fmt.Println(m)
    }

    结构体的定义和使用:

    Go中的结构体可以看作C++的类,而不是C中仅有数据成员的结构体

    package main
    
    import (
        "fmt"
    )
    
    func test(s student)  {
        fmt.Println(s)
    }
    
    type student struct {
        id int
        age int
        sex string
    }
    
    func main() {
        var s student
        s.id = 101
        s.age = 12
        s.sex = "man"
    
        fmt.Println(s)
    
        var s2 student = student{102, 13, "male"}
        s3 := student{103, 14, "man"}
        fmt.Println(s2, s3)
    
        s4 := s
        fmt.Println(s4)
    
        // 结构体的比较
        // !=
        // ==
    
        // 结构体切片
        //var ss []student
        ss := make([]student, 10)
    
       ss = append(ss, student{104, 11, "man"})
       fmt.Println(ss)
    
       m := make(map[int]student)
       m[1] = s
       m[2] = s2
       fmt.Println(m)
    }

    指针:

    package main
    
    import "fmt"
    
    // 指针作为函数参数
    func test(p *int) {
       *p = 99
       fmt.Println(*p)
    }
    
    // 切片指针作为函数参数
    func test2(p *[]int) {
       *p = append(*p, 999, 999)
    }
    
    type student struct {
       id int
       name string
    }
    
    func main() {
       var a int = 10
       // 定义整形指针变量 指向a的地址
       // 与C++类似
       var pa *int = &a
       fmt.Println(pa)
       *pa = 20
       fmt.Println(a)
    
       // 为指针变量创建一块内存空间
       var p1 *int
       //
       p1 = new(int)
       fmt.Println(*p1)
       fmt.Println(p1)
    
       test(&a)
       test(p1)
       fmt.Println(a)
       fmt.Println(*p1)
    
       // 数组指针
       var arr [5]int = [5]int{1, 2, 3, 4, 5}
       fmt.Println(arr)
       fmt.Printf("%p
    ", &arr)
    
       // 数组指针定义时给出的数组大小需要和赋值给他的数组大小一样
       // var parr *[5]int
       // parr = &arr
       parr := &arr
       fmt.Println(*parr)
       fmt.Println(parr)
       fmt.Printf("%T
    ", parr)
    
       // 切片指针
       var slice []int = []int{1, 2, 3, 4, 5}
       ppslice := &slice
       fmt.Println(slice)
       fmt.Println(*ppslice)
       fmt.Println(ppslice)// 二级指针
       fmt.Printf("%T
    ", ppslice)
       fmt.Println(*ppslice)
       // 切片名本身就是一个地址
       (*ppslice)[0] = 9
       fmt.Println(slice)
       // ppslice[0] = 9 error 和数组指针不同
       test2(ppslice)
       fmt.Println(slice)
    
       // 用new创建切片指针空间
       var p3 *[]int
       fmt.Printf("%p
    ", p3)
       p3 = new([]int)
       fmt.Printf("%p
    ", p3)
       *p3 = append(*p3, 1, 2, 3, 4, 5)
       for i := 0; i < len(*p3); i++ {
           fmt.Println((*p3)[i])
       }
    
       // 指针数组 指针切片
       a, b, c := 1, 2, 3
       var pointarr [3]*int = [3]*int{&a, &b, &c}
       *pointarr[0] = 99
       fmt.Println(a)
    
       // 指针切片
       var pointslice []*int
       pointslice = append(pointslice, &a, &b, &c)
       *pointslice[2] = 99
       fmt.Println(c)
    
       // 结构体指针
       var st student = student{101, "bob"}
       fmt.Println(st)
       var pstudent *student = &st
       pstudent.id = 102
       pstudent.name = "marrys"
       fmt.Println(st)
    
       // 多级指针
       x := 10
       px := &x
       ppx := &px
    
    }

    同名字段个匿名字段:

    package main
    
    import "fmt"
    
    type person struct {
        name string
        age int
        sex string
    }
    
    //  结构体嵌套
    type student struct {
        person// 匿名字段
        id int
        score int
        name string// 同名字段
    }
    
    type student2 struct {
        *person// 指针匿名字段
        id int
        score int
        name string// 同名字段
    }
    
    func main() {
        // var stu student = student{person{...}, ...}
        var stu student
        stu.id = 101
        stu.score = 100
        stu.name = "nana"
        stu.person.name = "lala"
        stu.person.age = 18
        stu.sex = "female"
        fmt.Println(stu)
    
        var stu2 student2
        //stu2.person.name = "kaka"// invalid memory address or nil pointer dereference
        stu2.person = new(person)
        stu2.name = "baba"
        stu2.person.name = "kaka"
        fmt.Println(stu2)
    }

    多重继承:

    package main
    
    import "fmt"
    
    type test1 struct {
        name string
        id int
    }
    
    type test2 struct {
        test1
        sex string
        age int
    }
    
    type test3 struct {
        test2
        score int
    }
    
    type test4 struct {
        test1
        test2
        score int
    }
    
    func main() {
        var s test3
        s.name = "asda"
        s.age = 19
        s.score = 1213
        fmt.Println(s)
    }

    结构体的方法的定义和使用:

    可以看作类的成员函数

    package main
    
    import "fmt"
    
    //func add(a, b int) int {
    //    return a + b
    //}
    
    // 起别名
    type Int int
    
    // 方法
    // func (方法接收者)方法名(参数列表)返回值类型
    func (a Int) add (b Int) Int {
        return a + b
    }
    
    type student struct {
        name string
        age int
        sex string
    }
    
    // 为结构体定义别名
    func (stu student) PrintInfo () {
        fmt.Println(stu.sex)
        fmt.Println(stu.name)
        fmt.Println(stu.age)
    }
    
    func (stu *student) Rename () {
        stu.name = "asdasdasd"
    }
    
    // 方法的继承
    type test struct {
        student
        index int
    }
    
    // 方法的重写
    func (t test) PrintInfo () {
        t.student.PrintInfo()
        fmt.Println(t.index)
    }
    
    // 方法类型和方法的值
    
    func main() {
        // 根据数据类型绑定方法
        var a Int = 1
         var b Int = 3
        fmt.Println(a.add(b))
    
         stu := student{"sdsad", 10, "male"}
         stu.PrintInfo()
         stu.Rename()
         fmt.Println(stu)
    
         var t test
         t.index = 101
         t.age = 19
         t.sex = "male"
         t.name = "Bbb"
         t.student.PrintInfo()
         t.PrintInfo()
         fmt.Println(t)
         t.Rename()
         fmt.Println(t)
    
         f1 := t.PrintInfo
         f2 := t.student.PrintInfo
        fmt.Printf("%T
    ", f1)
        fmt.Printf("%T
    ", f2)
    
         f1()
         f2()
    
    }

    接口的定义和使用:

    package main
    
    import "fmt"
    
    type person struct {
        name string
        sex string
        age int
    }
    
    type student struct {
        person
        score int
    }
    
    type teacher struct {
        person
        subject string
    }
    
    
    func (s *student)SayHello(){
        fmt.Printf("name: %s, score: %d
    ", s.name, s.score)
    }
    
    func (t *teacher)SayHello(){
        fmt.Printf("name: %s, subject: %s
    ", t.name, t.subject)
    }
    
    // 接口的定义
    // 接口定义了规则 方法实现了规则
    type TestInterface interface {
        // 方法的声明 没有具体实现 
        // 接口中定义的方法必须全部有具体的实现
        SayHello()
    }
    
    // 多态
    type Person interface {
        SayHello()
    }
    
    // 多态实现
    // 多态是将接口类型作为函数参数
    func SayHello(p Person){
        p.SayHello()
    }
    
    // 接口的继承
    type Speaker interface {
        Person
        Sing(string)
    }
    
    func (s *student)Sing(name string){
        fmt.Printf("Sing %s Name %s
    ", name, s.name)
    }
    
    func main () {
        var stu student = student{ person{"Bob", "male", 18}, 99 }
        var tea teacher = teacher{ person{"marry", "male", 28}, "Math" }
    
        stu.SayHello()
        tea.SayHello()
    
        // 定义接口类型
        var h TestInterface
        h = &stu
        h.SayHello()
    
        h = &tea
        h.SayHello()
    
        var p Person
    
        // 接口
        p = &student{ person{"Bob", "male", 18}, 99 }
        // 多态
        SayHello(p)
    
        p = &teacher{ person{"marry", "male", 28}, "Math" }
        SayHello(p)
    
        var s Speaker
        s = &stu
        s.SayHello()
        s.Sing("lalala")
    
        // 接口的转换
        // 将超集转换为子集
        p = s
        p.SayHello()
    
        // 不允许子集转换为超集
        // s = p // error
    
        // 空接口
        var i interface{}
        i = 10
        fmt.Println(i)
        i = "Hello"
        fmt.Println(i)
    
        // 类型断言
        if data, ok := i.(string); ok {
            fmt.Println("string ", data)
        }
    }

    异常处理:

    package main
    
    import (
        "fmt"
        "errors"
    )
    
    func test(a int, b int) (value int, err error) {
        //return a / b
        if b == 0 {
            err = errors.New("0不能作为除数")
            return
        } else {
            value = a / b
            return 
        }
    }
    
    func test2(a int, b int) (value int) {
        value = a / b
        return value
    }
    
    func test3() {
        fmt.Println("test3")
        // 调用panic程序自动终止
        panic("test3 panic")
    }
    
    func main() {
        value, err := test(10, 0)// 注意此处问题 0不能作为除数
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Println(value)
        }
        value1, err1 := test(10, 2)// 注意此处问题 0不能作为除数
        if err1 != nil {
            fmt.Println(err1)
        } else {
            fmt.Println(value1)
        }
    
        // panic异常处理
        //value2 := test2(10, 0)// panic: runtime error:
        //fmt.Println(value2)
    
        // 
        //test3()
    
        // 延迟调用
        // defer 在程序运行结束后再运行 先defer的后调用
        fmt.Println("Hello 1")
        defer fmt.Println("Hello 2")
        fmt.Println("Hello 3")
        defer fmt.Println("Hello 4")
        fmt.Println("Hello 5")
        
        a, b := 10, 20
        f := func(a int, b int) {
            fmt.Println(a)
            fmt.Println(b)
        }
        f2 := func() {
            fmt.Println(a)
            fmt.Println(b)
        }
        // 注意变量作用域
        defer f(a, b)// 输出10, 20
        defer f2()// 输出100, 200
    
        a, b = 100, 200
    
        fmt.Println("end...")
    }

    文件相关的操作:

    package main
    
    import (
        "fmt"
        "os"
        "io"
        //"bufio"
    )
    
    func main123() {
        // 创建文件 如果指定路径文件存在 则覆盖 否则创建
        fp, err := os.Create("../data/a.txt")
        // 文件创建失败
        if err != nil {
            fmt.Println("file create error")
            return
        }
    
        fmt.Println("file create successful")
    
        // 延迟调用 关闭文件
        // 占用内存和缓冲区
        // 文件打开上限
        defer fp.Close()
        
        // 写入文件
        fp.WriteString("hello
    ")
    
        // 返回写入字符数
        n, _ := fp.WriteString("world
    ")
        fmt.Println(n)
        // 一个汉字代表三个字符 换行算一个
        n, _ = fp.WriteString("你好
    ")
        fmt.Println(n)
    
        // 写入字符切片
        b := []byte{'a', 'b', 'c', 'd'}
        // 使用Write写入数据
        fp.Write(b)
    
        // 将字符串转为字符切片写入文件
        str := "HashSort"
        // 字符串和字符切片允许转换
        c := []byte(str)
        fp.Write(c)
    }
    
    func main124() {
        // 打开文件
        // OpenFile只能做打开操作 不能创建文件
        fp, err := os.OpenFile("../data/a.txt", os.O_RDWR, 6)
    
        if err != nil {
            fmt.Println("OpenFile error")
            return
        }
        defer fp.Close()
    
        // 获取文件字符个数
        n, _ := fp.Seek(0, io.SeekEnd)
        fmt.Println(n)
    
        b := []byte("HELLO
    ")
        // 使用WriteAt进行指定位置插入数据时会依次覆盖
        fp.WriteAt(b, 0)// 0表示offset 表示当前位置
    }
    
    func main() {
        // 只读方式打开文件
        fp, err := os.Open("../data/a.txt")
        // 文件打开失败的原因 文件不存在 没有打开权限 打开的文件数目达到上限
        if err != nil {
            fmt.Println("Open error")
            return
        }
        defer fp.Close()
    
        //b := make([]byte, 1024)
    
        // 读取文件
        //fp.Read(b)
        //fmt.Println(string(b))
    
        // 创建切片缓冲区
        //r := bufio.NewReader(fp)
        // 读取一行内容
        //b, _ := r.ReadBytes('
    ')
        //fmt.Println(string(b))
    
        b := make([]byte, 10)
    
        for {
            n, err := fp.Read(b)
            if err != nil {
                if err == io.EOF {
                    break
                }
            }
            fmt.Print(string(b[:n]))
        }
    }

    字符串的操作:

    包括判断子串是否存在、字符串拼接、查找子串位置等

    package main
    
    import (
        "fmt"
        "strings"
        "strconv"
    )
    
    func main() {
        str := "aaabbbcccddd"
        // 判断是否存在子串
        value := strings.Contains(str, "aaa")
    
        if value {
            fmt.Println("str存在aaa")
        } else {
            fmt.Println("str不存在aaa")
        }
        
        fmt.Println(value)
    
        s := []string{"aaa", "bbb", "ccc"}
        // 字符串拼接
        str = strings.Join(s, "-")
        fmt.Println(str)
    
        str = "123456789"
        // 查找子串位置 返回下标值 未找到返回-1
        idx1 := strings.Index(str, "456")
        idx2 := strings.Index(str, "436")
        fmt.Println(idx1)
        fmt.Println(idx2)
    
        // 重复字符串
        str = "ABCD"
        res := strings.Repeat(str, 3)
        fmt.Println(res)
    
        // 字符串转换
        // 将其他类型转换成字符串
        str = strconv.FormatBool(false)
        fmt.Println(str)
    
        str = strconv.FormatInt(123, 10)// 十进制数123
        fmt.Println(str)
    
        str = strconv.Itoa(12445)
        fmt.Println(str)
    
        str = strconv.FormatFloat(1.254, 'f', 5, 64)// 浮点数 1.254 小数位5 64位
        fmt.Println(str)
    
        // 字符串转换为其他类型
        str = "false"
        // 忽略错误信息
        //b, _ := strconv.ParseBool(str)
        b, err := strconv.ParseBool(str)
        //fmt.Println(b)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Println(b)
        }
    
        // 将字符串转化为整形
        str = "1010101"
        //a, _ := strconv.ParseInt(str, 2, 64)// 将2进制64位整数str转为10进制数
        a, _ := strconv.ParseInt(str, 10, 64)// 将10进制64位整数str转为10进制数
        fmt.Println(a)
    
        str = "12.35545"
        d, _ := strconv.ParseFloat(str, 64)
        fmt.Println(d)
    
        // Append
        e := make([]byte, 0, 1024)
        // 将bool类型放在指定切片中
        e = strconv.AppendBool(e, false)
        e = strconv.AppendInt(e, 123, 10)
        e = strconv.AppendFloat(e, 1.234, 'f', 5, 64)
        fmt.Println(string(e))
    
    }
    转载请注明出处
  • 相关阅读:
    android kl文件
    ELF文件结构描述
    jquery开头
    win7无声音显示“未插入扬声器或耳机” 怎么解决
    xhtml头文件设置
    break和continue的区别
    php目录函数
    mysql语法
    php中怎么导入自己写的类
    截取文件后缀名
  • 原文地址:https://www.cnblogs.com/lnlin/p/14903466.html
Copyright © 2011-2022 走看看