Go基础--笔记

Posted 荒唐了年少

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n", &arr)

   // 数组指针定义时给出的数组大小需要和赋值给他的数组大小一样
   // var parr *[5]int
   // parr = &arr
   parr := &arr
   fmt.Println(*parr)
   fmt.Println(parr)
   fmt.Printf("%T\\n", parr)

   // 切片指针
   var slice []int = []int{1, 2, 3, 4, 5}
   ppslice := &slice
   fmt.Println(slice)
   fmt.Println(*ppslice)
   fmt.Println(ppslice)// 二级指针
   fmt.Printf("%T\\n", 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\\n", p3)
   p3 = new([]int)
   fmt.Printf("%p\\n", 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\\n", f1)
    fmt.Printf("%T\\n", 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\\n", s.name, s.score)
}

func (t *teacher)SayHello(){
    fmt.Printf("name: %s, subject: %s\\n", 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\\n", 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 go语言学习笔记 — 基础 — go工具:go工具

go语言学习笔记 — 基础 — go工具:一键获取源代码,编译并安装 —— go get

go语言学习笔记 — 基础 — go工具:性能分析,发现代码性能问题的具体位置 —— go pprof

go语言学习笔记 — 基础 — go工具(5.1):单元测试 —— 测试和验证代码的框架

go语言学习笔记 — 基础 — go工具(5.2): 基准测试 (性能测试)—— 获得代码内存占用和运行效率的性能数据

go语言学习笔记 — 基础 — go工具:编译 —— go build