Go语言基础1

Go语言程序

语法要求:严格区分大小写;一行一行编译,一行只写一条语句;go语言定义的变量或者import的包如果没有使用,代码不能编译通过

转义字符的使用:回车\r 从当前行的最前面开始输出,覆盖掉以前的内容

#编译并生成可执行文件
go build 文件名.go
#编译生成可执行程序并运行
go run 源码文件.go

go env 查看环境信息

go text

  • go语言自带测试工具,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件

常用命令行

关键字

go语言关键字以及使用方式

数据类型

1命名规则

  • 数字不能开头

  • 区分大小写

  • 允许使用字母数字下划线

  • 不允许使用关键字

  • 见名知意

2基本数据类型

  • 派生数据类型

    • 指针,数组,结构体,通道,切片,函数,接口,map

  • 基本数据类型

    • 布尔,数值,字符串

驼峰式命名:

小驼峰如myName可以在包内部使用,大驼峰如MyName可以被外部函数使用

ASCII码:0-31控制字符 使用转义字符表示内容,32-126 默认字符

127 del 字符

一个中文汉字占三个字符

3类型转换

package main
​
import "fmt"
​
func main() {
    //去市场买菜
    price := 3.25
    weight := 5
    //fmt.Printf("%T\n", price)
    //fmt.Printf("%T\n", weight)
    //sum := price * float64(weight)
​
    //  浮点型转整型,会丢失精度
    sum := int(price * float64(weight))
    fmt.Println(sum)
}
func main() {
    // type tune = int32  两个数据类型可以计算
    ch := 'A'  //rune == int32
    var b int32 = 100
    fmt.Println(ch+b)
}

4派生数据类型

数组

一组具有相同数据类型在内存中有序储存的数据集合

数组的长度在定义后不可以修改

func main() {
    // type tune = int32  两个数据类型可以计算
    //ch := 'A'  //rune == int32
    //var b int32 = 100
    //fmt.Println(ch+b)
    //var arr []int 默认值为0
    //使用数组名+下标进行数组初始化   下标是从0开始的到数组最大元素个数-1
    //var arr [10]int
    //arr[0] = 123
    arr := [10]int{1,2,3,4,5,6,7,8,9,10}
    //fmt.Println(len(arr))
    //遍历数组元素
    //for i := 0;i < len(arr);i++{
    //  fmt.Println(arr[i])
    //}
    for i, j := range arr{
        fmt.Println(i, j)
    }
}

运行结果如下

  • 如果不赋值的话,默认值为0

 

数组内存存储

func main() {
    arr := [10]int{1,2,3,4,5,6,7,8,9,10}
    for i := 0;i < len(arr);i++{
        //&取地址运算符
        fmt.Println(&arr[i])
    }
}

切片

一组具有相同数据类型在内存中有序储存的可扩容的数据集合

func main4() {
    //切片的定义和使用
    //var 切片名 []数据类型
    //var slice []int
    //var slice []int = make([]int, 10)
    //slice[0]=123
    var slice []int
    fmt.Println(len(slice)) //计算长度
    fmt.Println(cap(slice)) //计算容量
    //使用append对切片进行扩容
    slice = append(slice, 1,2,3,4,5)
    fmt.Println(len(slice))
    fmt.Println(cap(slice))
    fmt.Println(slice)
}

切片的截取

//func main5() {
//  //切片的截取
//  slice := []int{1,2,3,4,5,6,7,8,9,10}
//  //左闭右开  包含起始下标 不包含结束下标
//  //s := slice[2:7]
//  //s := slice[:5]
//  s := slice[2:5:6] //实际容量=容量-起始下标
//  s[0] = 333
//  //切片的截取  是将新的切片指向原切片的内存地址  修改一个会影响另一个
//  fmt.Println(s)
//  fmt.Println(slice)
//}

切片的拷贝

func main() {
    slice := []int{1,2,3,4,5}
    //s := slice
    //s[2] = 33
    //在储存两个内容完全相同  改变一个值不会相互影响
    s := make([]int, 5)
    copy(s, slice)
    s[2] = 33
    fmt.Println(s)
    fmt.Println(slice)
}

map

//func main7() {
//  //map的定义
//  //var 字典名 map[键类型]值类型
//  //var m map[int]string = make(map[int]string, 10)
//  //m[1001] = "键盘"
//  //m[8888] = "鼠标"
//  //map是无序的集合
//  m := map[int]string{1:"dfg", 2:"freg"}
//  for k, v := range m{
//      fmt.Println(k, v)
//  }
//}
func main() {
    m := make(map[int]string)
    m[1] = "sdgf"
    m[2] = "trhh"
    if v, ok := m[1];ok{
        fmt.Println(v)
    }else{
        fmt.Println("不存在")
    }
    delete(m, 1)
    fmt.Println(len(m))
    fmt.Println(m)
}

new和make的区别:

  • 两者都是用来做内存分配的

  • make只用于slice,map 以及channel的初始化,返回的还是这三个引用类本身

  • 而new

  • 用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针

指针

go语言中函数传参都是值拷贝,记住两个符号:&(取地址)和*(根据地址取值)

//func main9() {
//  a := 10
//  //取出变量a所在内存的地址
//  var p *int = &a
//  fmt.Println(p)
//  fmt.Println(&a)
//  //通过指针间接修改变量的值
//  *p = 123
//  fmt.Println(p)
//}
func main() {
    //error
    //定义指针 默认值为nil 指向内存地址编号为0的空间 内存地址0-255为系统占用 不允许用户读写操作
    //var p *int
    //*p = 123
    //fmt.Println(*p)
    //开辟数据类型大小的空间  返回值为指针类型
    //new(数据类型)
    var p *int
    p = new(int)
    *p = 123
    fmt.Println(*p)
​
}

流程控制

if语句

//if 表达式{} 如果表达式为真 执行{}的代码
//  //if 表达式{代码1} else{代码2} 如果表达式为真,执行代码1
//
//  //score := 0
//  //fmt.Scan(&score)  //阻塞式请求
//  //if score > 700{
//  //  fmt.Println("我问问")
//  //}else if score > 600{
//  //  fmt.Println("而政府")
//  //}else{
//  //  fmt.Println("梵蒂冈")
//  //}

switch语句

//  //day := 0
//  //var m int
//  //fmt.Scan(&m)
//  //switch m {
//  //case 1, 3, 5, 7, 8, 10, 12:
//  //  day = 31
//  //  //fallthrough //执行完当前分支 继续向下执行
//  //case 2:
//  //  day = 29
//  //}
//  //fmt.Println(day)
//  //浮点型因为精度问题可能在switch中认为是同一个值
//  //pi := 3.14
//  //switch pi{
//  //case 3.14:
//  //  fmt.Println(pi)
//  //case 3:
//  //  fmt.Println(pi)
//  //}
//  //score := 0
//  //fmt.Scan(&score)
//  //switch {
//  //case score > 700:
//  //  fmt.Println("df")
//  //case score > 600:
//  //  fmt.Println("fs")
//  //default:
//  //  fmt.Println("cds")
//  //}
​

for语句

func main() {
    /*
    for 表达式1:表达式2:表达式3{
        代码体
    }
    for 表达式{
        代码体
    }
    for range 集合{
        代码体
    }
     */
    //sum := 0
    //for i := 1;i <= 100; i++{
    //  sum += i
    //}
    //fmt.Println(sum)
    //嵌套循环
    //for i := 1;i<=5;i++{
    //  for j := 1;j<=5;j++{
    //      fmt.Println(i,j)
    //  }
    //}
    //冒泡排序
    slice := []int{6, 4, 8, 3, 5}
    for i := 0;i 

跳出语句

break语句:在循环语句中使用break跳出语句

continue语句:在循环语句中,如果希望立即终止本次循环,并执行下一次循环,就需要用到continue

函数

函数定义

func 函数名(参数)(返回值){
    函数体
}
//func sayHello(){
//  //定义不需要string类型的name参数
//  fmt.Println("hello")
//}
//func sayHello2(name string){
//  fmt.Println("hello", name)
//}
//go语言中没有默认参数
//可变参数与不可变参数放在一起时,可变参数放在最后
func intSum(a int, b int) int {
    sum := a+b
    return sum
}
//也可以定义多返回值
func calc(a, int b) (sum, sub int){
    sum = a + b
    sub = a - b
    return 
}
func main() {
    x, y := calc(100, 200)
    fmt.Println(x, y)
//  fmt.Println(intSum(2,3))
}

defer语句

先被defer的语句最后执行,最后被defer的语句最先被执行

func main() {
    //defer:延迟执行
    fmt.Println("start...")
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
    fmt.Println("end")
    //fmt.Println(intSum(2,3))
}

函数进阶

var num = 10
func testGlobal(){
    num := 100
    name := "wowowo"
    //可以在函数中使用变量
    //先在自己函数中查找,找到了就用自己函数中的
    //函数中找不到变量就往外层找
    fmt.Println("数字是:", num)
    fmt.Println(name)
}
func main() {
    testGlobal()
}
  • 闭包和匿名函数

    //匿名函数和闭包
    //定义一个函数它的返回值是一个函数
    //把函数作为返回值
    func a(name string) func(){
        //name := "fdsf"
        return func() {
            fmt.Println("hello", name)
        }
    }
    func main() {
        //闭包=函数+外层变量的引用
        r := a("jncxu") //r是一个闭包
        r()//相当于执行了a函数内部的匿名函数
    }

     

  • panic和recover

    go语言中没有异常机制,但是使用panic和recover模式处理机制错误。panic可以在任何地方引发,但recover只有在defer调用的函数中有效

    func a(){
        fmt.Println("func")
    }
    func b(){
        defer func() {
            err := recover()
            if err != nil{
                fmt.Println("func b error")
            }
        }()
        panic("panic in b")
    }
    func main() {
        a()
        b()
    }

    运行结果

    GOROOT=G:\golang_env #gosetup
    GOPATH=D:\work\goCode #gosetup
    G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup
    C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup
    func
    func b error
    ​
    Process finished with exit code 0

结构体

类型别名和自定义类型

  • 自定义类型 可以使用type关键字来自定义类型

    type MyInt int 
  • 类型别名 规定:TypeAlias只是Type的别名,就像一个人有小名,大名,英文名但所有名字都是一个人

    type TypeAlias = Type
  • 类型定义和类型别名的区别

    type MyInt int
    type MiInt = int
    func main() {
        var i MyInt
        var j MiInt
        fmt.Printf("type of i:%T\n", i)
        fmt.Printf("type of j:%T\n", j)
    ​
    }

    输出

    GOROOT=G:\golang_env #gosetup
    GOPATH=D:\work\goCode #gosetup
    G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup
    C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup
    type of i:main.MyInt
    type of j:int
    ​
    Process finished with exit code 0

结构体定义与实例化

  • 定义 go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这 种数据类型叫做结构体(struct) t 通过struct来实现面向对象

  • 使用type和struct关键字来定义结构体

    //定义结构体
    type person struct {
        name, city string
        age       int8
    }
  • 实例化

    type person struct {
        name, city string
        age       int8
    }
    ​
    func main() {
        var p person
        p.name = "fncsdjf"
        p.age = 19
        p.city = "fds"
        fmt.Printf("p=%#v\n", p)
        fmt.Println(p.name)
    }
  • 匿名结构体

    func main() {
        var user struct{
            name string
            married bool
        }
        user.name = "fdsf"
        user.married = false
    }

结构体的初始化

  • 键值对初始化

  • 值的列表进行初始化

    func main() {
        //键值对初始化
        //a := &person{
        //  name: "你你你",
        //  city: "背景",
        //  age: 19,
        //}
        //fmt.Printf("%#v\n", a)
        //值的列表进行初始化
        b := &person{
            "我问问",
            "背景",
            19,
        }
        fmt.Printf("%#v\n", b)
    }
  • 注意

    • 必须初始化结构体的所有字段

    • 初始值的填充顺序必须与字段在结构体中的声明顺序一致

    • 该方式不能和键值初始化方式混用

构造函数

type person struct {
    name, city  string
    age         int8
}
//构造函数
func newPerson(name, city string, age int8) *person{
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}
func main() {
    c := newPerson("gfbb", "vcv", int8(19))
    fmt.Printf("type:%T value:%#v\n", c, c)
}

你可能感兴趣的:(golang)