0. 环境准备
1. 安装
- 下载并安装 goland ide 编辑器
 
- 下载 golang 文件并安装
 
2. 测试
1. go
- 每个 go 源代码文件开头必须是,package 声明,代表数据哪个包
 
- 声明 main,代表可以编译
 
- 有且只有一个 main 函数,主函数
 
- 导入的包必须使用,不使用会报错
 
- 左括号不能单起一行,否则会报错
 
// test.go
package main
import "fmt"
func main() {
    fmt.Println("hello world!")
}
2. go编译器测试
go env
3. goland编辑器
// 命令行
go env
go build test.go
./test
// 或者
go run test.go
web框架
- beego
 
- gin
 
1. 基础语法
1. 变量
1. go关键字
| case | 
defer | 
go | 
map | 
struct | 
| chan | 
else | 
goto | 
package | 
switch | 
| const | 
fallthrough | 
if | 
range | 
type | 
| continue | 
for | 
import | 
return | 
var | 
2. 预定义的名字
1. 内建常量(4)
2. 内建类型(20)
- int、int8、int16、int32、int64(5)
 
- uint、uint8、uint16、uint32、uint64 、uintptr(6)
 
- float32、float64、complex64、complex128 (4)
 
- bool、byte、rune、string、error(5)
 
3. 内建函数(13)
- make、len、cap、new、append、copy、close、delete
 
- complex、real、imag
 
- panic、recover
 
3. 示例
package main
import ("fmt")
func main(){
    // 直接定义
    var a int
    var b int
    // 一次定义多个
    var c, d int
    // 括号里
    var(
        e int
        f int
    )
     fmt.Println(a, b, c, d, e, f)
}
package main
import ("fmt" "reflect")
// 变量
func main(){
    // 方式一
    var v1 int = 10
    // 方式二:编译器自动推到类型
    var v2 = 5
    fmt.Println(reflect.TypeOf(v1))
    fmt.Println(reflect.TypeOf(v2))
    // 方式三: :=  声明并赋值
    v3 := 1
    fmt.Println(reflect.TypeOf(v3))   
    // 方式四
    var v4, v5, v6
    v4, v5, v6 = 1, 2,3
    fmt.Println(v4, v5, v6)
}
package main
import ("fmt")
// (int, string) 定义函数的返回值,返回 2 个值
func test()(int, string){
    return 666, 'xixi'
}
func main(){
    // 调用函数并接收返回值。定义变量接收
    // _ 表示匿名函数,防止编译不通过
    i, _ := test()
    fmt.Println(i)
}
2. 常量和枚举
1. 常量
1. 直接定义
package main
import "fmt"
// 常量
func main(){
    const pi = 3.1415926
    fmt.Println(pi)
}
2. 通过函数
package main
import "fmt"
const pi = 3.1415926
func const(){
    const(
        pi = 3.14
    )
    // 就近原则
    fmt.Println(pi)
}
func main(){
    const()
}
3. iota常量生成器
// ista = 0 的常量
func enums3(){
    const(
        python = iota
        java
        golang
    )
    fmt.Printzhln(python, java, golang)
}
func enums4(){
    const(
        // 位运算,b 左移
        b = 1 << (10 * iota)
        kb
        mb
    )
    fmt.Println(b, kb, mb)
}
4. 常量补充
package main
import (
    "fmt"
    "reflect"
)
func main(){
    enums()
    fmt.Println(name)
}
func enums() {
    const(
        a = iota
        b
        c = 9
        d = iota
        e
        f
    )
    fmt.Println(a, b, c, d, e, f)
    fmt.Println(reflect.TypeOf(f))
}
var name string = "echo"
2. 枚举
package main
import "fmt"
// 定义枚举类型
func enums(){
    const(
        python = 0
        java = 1
        golang = 2
    )
    fmt.Println(python, java, golang)
}
// 定义枚举类型 2
func enums2(){
    const(
        python = 0
        // 默认和上面的值一样
        java
        golang = 1
        php
    )
    fmt.Println(python, java, golang, php)
}
func main(){
    enums()
    enums2()
    enums3()
}
3. 基本数据类型
1. 整型
- int32、int64
 
- uint32、uint64
 
- int:一个字长
 
package main
import ("fmt", "reflect")
// 整型
func main(){
    // int 和 uint,一个字长
    var v1 in32
    v1 = 123
    v2 := 64
    mt.Println(reflect.TypeOf(v1))
    fmt.Println(reflect.TypeOf(v2))
}
2. 浮点型
- float32 和 float64
 
- int(a):强制类型转换s
 
func main(){
    var v3 float32
    v3 = 12
    // 编译器自动推断成 一个字长
    v4 := 12.5
    mt.Println(reflect.TypeOf(v3))
    fmt.Println(reflect.TypeOf(v4))
    
    var c float32 = 1
    fmt.Println(unsafe.Sizeof(c))
    
    // 不同类型的不能想加,编译错误
    var a = 1
    fmt.Println(a + v4)
    // 可以类型强制转换
    fmt.Println(a + int(v4))
}
3. bool
- true 和 false
 
- 注意:定义的 bool 类型不能赋值给其他类型的值
 
package main
func main(){
    var v1 bool
    v1 = true
    // 可以使用表达式
    v2 := (1==2)
    fmt.Println(v1, v2)
    fmt.Println(reflect.TypeOf(v2))
    // 取反
    v3 := !v2
    fmt.Println(v3)
    // 逻辑元算符
    if v3 == true && v2 == false{
        fmt.Println("right")
    }
}
4. byte 和 string
- byte:字符,单引号
 
- string:字符串,双引号
 
package main
// byte 类型
func main(){
    // 字符和字符串
    var ch byte
    // 字符用单引号,字符串使用双引号
    ch = 'a'
    fmt.Println(ch)
    fmt.Printf("ch = %c\n", ch)
}
package main
import "fmt"
func main(){
    var str string
    str = 'abc'
    fmt.Printf("%c\n", str[0])
    // uint8 与 byte 一样
    fmt.Printf(reflect.TypeOf(str[0]))
    // 反引号,不进行转义
    str2 := `hello
    abc \n \r ...`
    fmt.Println(str2)
}
5. 类型别名
func main(){
    // 定义 myint 类型,实际就是 int
    type myint int
    var i myint = 100
    fmt.Println(i)
    // main.myint,拥有原来类型的所有性质,并且可以自定义方法
    fmt.Println(reflect.TypeOf(i))
}
6. 类型转换
func main(){
    var ch byte = 'a'
    // 强制转换
    var i int = int(ch)
    fmt.Println(i)
}
4. fmt 包
- 输入、输出
 
- println:默认有换行
 
- print 和 printf:没有换行
 
package main
import "fmt"
func main(){
    a := 15
    // 输出
    fmt.Printf("a=%d\n", a)
    // 输入
    var v int
    fmt.Printf("请输入一个整型:")
    fmt.Scan(&v)
    fmt.Println(v)
}
| %v | 
按值的本来值输出 | 
| %+v | 
在 %v 基础上,对结构体字段名和值进行展开 | 
| %#v | 
输出 Go 语言语法格式的值 | 
| %T | 
输出 Go 语言语法格式的类型和值 | 
| %% | 
输出 % 本体 | 
| %b | 
整型以二进制方式显示 | 
| %o | 
整型以八进制方式显示 | 
| %d | 
整型以十进制方式显示 | 
| %x | 
整型以十六进制方式显示 | 
| %X | 
整型以十六进制、字母大写方式显示 | 
| %U | 
Unicode 字符 | 
| %f | 
浮点数 | 
| %p | 
指针,十六进制方式显示,并加上前导的0x | 
5. 流程控制
1. 选择
1. if...else
func main(){
    const filename = 'abc.txt'
    // 选择方式一
    content, e = ioutil.ReadFile(filename)
    // 相当于 None
    if e!= nil{
        fmt.Pringln(e)
    }else{
        fmt.Printf("%s\n", content)
    }
    
    // 选择方式二
    if content, e = ioutil.ReadFile(filename): e != nil{
        fmt.Pringln(e)
    }else{
        fmt.Printf("%s\n", content)
    }
}
2. switch
package main
import "fmt"
func main(){
    res := grade(-1)
    fmt.Println(res)
}
func grade(score int)(string){
    // 定义一个 string 用于返回
    res := ""
    switch {
    case score < 0 || score > 100:
        res = "输入有误"
        // 若想继续执行,添加 fallthrough
    case score < 60:
        res = "不及格"
    case score < 80:
        res = "良好"
    default:
        res = "优秀"
    return res
    }
}
2. 循环
package main
import "fmt"
func main(){
    sum(100)
    sum2(100)
}
func sum(num int){
    sum := 0
    for i := 0; i <= num; i++ {
        sum += i
    }
    fmt.Println(sum)
}
func sum2(num int){
    i := 0
    sum := 0
    for i <= num{
        sum += i
        i ++
    }
    fmt.Println(sum)
}
func main(){
    s := 'abc'
    for i, c := range s{
        fmt.printf("%d, %c\n", i, c)
    }
}
3. 跳转
func main(){
    for i := 0; i<5; i++{
        fmt.println(i)
        goto OUT
    }
    
    OUT:
    fmt.println("yes")
}
2. 函数
1. 自定义函数
- 函数和字段,名字首字母小写代表的是private(只有包内才能调用),大写为public
 
// 也可以这样定义
func example(v1, v2 int){}
// 不定参
func example(args ... int){
    for _, n := range args{
        fmt.Println(n)
    }
}
// 返回多个值
func example()(int, string){}
// 返回一个值
func example() int {}
// 返回值,定义变量名
func example()(a int, str string){
    a = 123
    str = 'abc'
    return
}
package main
import "fmt"
func main() {
    res := rsum(100)
    fmt.Println(res)
}
// 循环版
func sum(num int) (res int) {
    res = 0
    for i := 1; i <= num; i++ {
        res += i
    }
    return
}
// 递归版
func rsum(num int) (res int) {
    if num == 1 {
        return 1
    }
    return num + rsum(num-1)
}
2. defer 关键字
1. 功能
- defer?于延迟一个函数或者方法的执行
 
- defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁
 
- 通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放
 
- 释放资源的defer应该直接跟在请求资源的语句后,以免忘记释放资源
 
2. 单个defer
func main(){
    // 延迟执行,一般用于资源关闭
    defer fmt.Println("defer")
    fmt.Println("main")
}
2. 多个defer
func main(){
    defer fmt.Println("a")
    defer fmt.Println("b")
    defer test(0)
    defer fmt.Println("c")
}
// c b a
func test(num int){
    fmt.Println(100/num)
}
3. 复合数据类型
| pointer | 
指针 | 
nil | 
| array | 
数组 | 
0 | 
| slice | 
切片 | 
nil | 
| map | 
字典 | 
nil | 
| struct | 
结构体 | 
- | 
1. 指针
- &a:代表取a的地址
 
- 指针和变量是配合使用的
 
- 指针也有类型,只能指向定义类型的数据,如果是对象定义类名
 
1. 定义和初始化
func main(){
    a := 10
    var p *int = &a
    fmt.Printf("%x\n", p)
    fmt.Println(*p)
    // 修改数据
    *p = 20
    fmt.Println(*p, num)
    
    b := "abc"
    var ip *string = &b
    fmt.Printf("%X\n", ip)
    fmt.Println(*ip)
}
2. 空指针
// 是否为空的判断
if ptr == nil{
    fmt.Println("ptr指针为空")
}
3. 值传递和引用传递
- 值传递:相当于是变量的副本,不会修改原来的变量
 
- 引用传递:传递的是变量的地址,相当于是指针
 
- go语言,函数传参都是值传递,会单独开启一块内存空间
 
// c 语言版本
void pass_by_val(int a){
    a++;
}
void pass_by_ref(int *a){
    (*a)++;
}
int main(){
    int a = 3;
    pass_by_val(a);
    printf("%d\n", a);
    pass_by_ref(&a);
    printf("%d\n", a);
}
// go 语言版本的交换数据
func swap(a, b *int){
    *a, *b = *b, *a
}
func main(){
    a, b := 3, 4
    swap(&a, &b)
    fmt.Println(a, b)
}
2. new() 和 make()
- new()用来分配内存,但与其他语言中的同名函数不同,它不会初始化内存,只会将内存置零
 
- make(t Type, size ... IntergerType)会返回一个指针,该指针指向新分配的,类型为 t 的零置,适用于创建结构体
 
- make()的目的不同于new(),它只能创建 slice、map、channel,并返回类型为T(非指针)的已初始化(非零值)的值
 
- new是一般是创建对象的,也可以创建变量。
 
func main(){
    // new
    p := new([] int)
    fmt.Println(p)
    // make,   类型, 长度,容量
    v := make([] int, 10, 50)
    fmt.Println(v)
}
2. 数组
1. 声明数组
1. 一维数组
// 数据定义
func main(){
    // 直接定义
    var arr1 [10] int  
    // :=
    arr2 := [3]int{1,2,3}
    // 省略大小,编译器自动推断
    arr3 := [...]int{1,2,3,4,5}
    fmt.Println(arr1, arr2, arr3)
}
2. 二维数组
func main(){
    var grid [4][5] int
    fmt.Println(grid)
}
2. 数组遍历
// 数据定义
func main(){
    arr := [...]int(1,2,3,4,5)
    // 方式一
    for i:=0; i<len(arr3); i++{
        fmt.Println(arr[i])
    }
    // 方式二
    for _, v := range arr{
        fmt.Println(v)
    }
}
// 数组的传递是值传递
package main
import "fmt"
func printArr(arr [5]int) {
    arr[0] = 18
    for _, v := range arr {
        fmt.Println(v)
    }
}
func main() {
    arr := [...] int{1, 2, 3, 4, 5}
    printArr(arr)
    for _, v := range arr {
        fmt.Println(v)
    }
}
package main
import "fmt"
func printArr(arr *[5]int) {
    arr[0] = 18
    for _, v := range arr {
        fmt.Println(v)
    }
}
func main() {
    arr := [...] int{1, 2, 3, 4, 5}
    printArr(&arr)
    for _, v := range arr {
        fmt.Println(v)
    }
}
3. 数组切片
- 切片操作和 python 中的 list 类似,但底层不同,go的切片是 view 操作,类似数据库的 view 操作
 
- 切片结果是 slice 类型:[]类型(如:[]int),此时是对 array 的引用
 
- 切片索引不能超过数组的最大索引值
 
func main(){
    arr := [...]int{1,2,3,4,5,6,7,8,9}
    fmt.Println(arr[2:6])
}
3. slice
1. 定义
- 数组的长度固定,go 提供了数组切片(slice)
 
- 取值时,索引值超出范围会报错
 
func main(){
    // 声明切片,只是比数组少了长度
    var s1 [] int
    // :=
    s2 := []int{}
    // make()
    var s3 []int = make([]int, 0, 0)  // 与下一行等价
    var s3 []int = make([]int, 0)
    // 声明并初始化
    s4 := []int{1,2,3,4}
}
2. 内置函数
1. append()
func main(){
    var s1 []int
    s1 = append(s1, 1)
    fmt.Println(s1)
    s1 = append(s1, 2, 3...)
    fmt.Println(s1)
    // 用make创建指定大小的切片
    s2 := make([]int, 5)
    s2 = append(s2, 6)
    fmt.Println(s2)
    // 创建并初始化
    s3 := []int{1,2,3}
    s3 = append(s3, 4,5)
    fmt.Println(s3)   
}
- 切片补充
 
- 可以在切片的基础上继续切片,只要不超过原数组就行
 
// 切片是 view 操作
func main(){
    // 数组
    arr := [...]int{0, 1,2,3,4,5,6,7}
    s1 := arr[2:4]
    fmt.Println(s1, s1[0], s1[1], s1[:6])
    fmt.Println(len(s1))
    fmt.Println(cap(s1))            // 容量到原数组结尾
}
2. copy()
func main(){
    arr := [...]int{0,1,2,3,4,5,6,7,8,9}
    s1 := arr[8:]  // 8,9
    s2 := arr[:5]   // 0,1,2,3,4
    // 将第二个切片元素copy到第一个
    // si从头开始覆盖,索引对应位置赋值,不同位置不变
    copy(s2, s1)
}
4. Map
1. 定义
- 类似python的dict
 
- 无序的健值对的集合,可以通过key找到value值
 
func main(){
    // 定义map,直接声明
    var m1 map[int] string
    var m11 map[int] string = map[int]string{1:"abc", 2:"def"}
    // :=
    m2 := map[int]string{}
    m2 := map[int]string{1:"abc", 2:"def"}
    // make()
    m3 := make(map[int]string)
    // 指定容量的 make()
    m4 := make(map[int]string, 10)
    fmt.Println(m1, m2, m3)
    fmt.Println(m4, len(m4),)
}
2. 键值操作
func main(){
    m1 := map[int]string{1:"北京", 2:"上海", 3:"广州"}
    // 增加
    m1[4] = "杭州"
    // 修改
    m1[1] = "beijing"
    fmt.Println(m1)
    // 删除
    delete(m1, 2)
    fmt.Println(m1)
}
3. 遍历
func main(){
    m1 := map[int]string{1:"北京", 2:"上海", 3:"广州"}
    // 遍历
    for k, v := range m1{
        fmt.Println(k, v)
    }
    // 判断某个key对象的value是否存在
    val, ok := m1[1]
    fmt.Println(val, ok)
}
5. 结构体
1. 定义和初始化
// 定义 type 结构体名 struct{}
// 学生的结构体
type Student struct{
    id int
    name string
    gender byte
    age int
    address string
}
func main(){
    // 顺序初始化
    var s1 Student = Student{1, "john", 'f', 20, "beijing"}
    // 指定初始化
    s2 := Student{id:2, age:20}
    // 结构体作为指针变量初始化
    var s3 *Student = &Student{3, "tom", 'm', 20, 'bj'}
    fmt.Println(s1, s2, s3)
    fmt.Println(s1.id, s1.name)
    // 获取指针对象的字段
    fmt.Println((*s3).name)
    fmt.Println(s3.name)      // 底层会转为 (*s3).name
    
}
2. 结构体参数
// 定义 type 结构体名 struct{}
// 学生的结构体
type Student struct{
    id int
    name string
    gender string
    age int
    address string
}
// 定义传递学生对象的方法
func temStudent(tmp Student){
    tmp.id = 250
    fmt.Println("temStudent", tmp)
}
// 传递指针对象
func pStudent(p *Student){
    p.id = 300
    fmt.Println("pStudent", p)
}
func main(){
    // 顺序初始化
    var s1 Student = Student{1, "john", "female",  20, "beijing"}
    // 传递非指针
    temStudent(s1)
    fmt.Println("main", s1)
    // 传递非指针
    pStudent(&s1)
    fmt.Println("main", s1)
}
Go基础
原文:https://www.cnblogs.com/henryw/p/11587654.html