Go 语言入门指南:基础语法和常用特性解析| 青训营

75 阅读5分钟

基础知识回顾

String

  1. for range遍历 string 得到的是 rune ,通过索引访问string中的元素得到的是byte

    // int转string,内部调用了 FormatInt
        var s string = strconv.Itoa(i) 
     
     // int64转string   这个10是十进制的意思
        s = strconv.FormatInt(i64,10) 
    
     // string转int
        i,err = strconv.Atoi(s) 
        
     // string 转 int64
        i64,err = strconv.ParseInt(s,10,64)
    
    // 保留两位小数
        var f float64 = 8.123456789
    	s = strconv.FormatFloat(f,'f',2,64) 
    // string 转 float
        f,err = strconv.ParseFloat(s,64) 
    

格式化输出

输出格式         输出内容
%t				单词true后缀false
%b				表示二进制
%d				表示十进制
%e				有6位小数部分的科学计数法,比如 -1234.456e+78
%f				有6位小数部分,比如  123.456123
%g				根据实际情况采用 %e或者%f格式(获取更简洁、准确的输出)
%s				直接输出字符串或者字节数组
%v				值的默认格式表示
%+v				类似%v,但输出结构体时会添加字段名
%#v				值的Go语法表示
%T				值的类型的Go语法表示

数组

  1. 数组在声明时必须指定长度,长度不可改变,数组类型包含元累类型和数组长度

  2. 数组是块连续的内存空间,数组的地址就是首元素的地址

  3. var arr2 =[5]int{}
    var arr3 =[5]intf3,2}//给前2个元素赋值
    var arr4 =[5]int{2:15,4:30}//指定index赋值
    var arr5 =[..]int{3,2,6,5,4}//根据0里元素的个数推断出数组的长度
    

切片

type slice struct{     //切片本质是结构体
    array unsafe.Pointer	//指针
    len int	//长度
    cap int	//容量
}

image-20230802182047185.png

初始化切片

var s []int//切片声明,len=cap=0
s=[]int{} //初始化,len=cap=0
s=make([]int,3)//初始化,len=cap=3
s=make([]int,3,5)//初始化,len=3,cap=5
s=[]int{1,2,3,4,5] //初始化,len=cap=5

截取子切片

arr :=make([]int,3,5) // len=3  cap=5  
crr :=arr[0:2]	// 截取 0到2 位置

//此时crr 与 arr共享底层内存   也就是说如果crr改变 ,arr也会跟着改变
crr[1] =8
crr = append(crr,4)
crr = append(crr,4)  //当超出arr的cap,crr与arr内存分离 这时就 互不影响了

image-20230802183014322.png

map

· go map的底层实现是hash table,根据key查找value的时间复杂度是O(1) ,但是扩容成本高因为一旦槽位变化,每个值所存放的位置也要变化

// 定义:
// 使用 make() 函数创建一个空的 map
myMap := make(map[keyType]valueType)

// 或者直接声明并初始化 map
myMap := map[keyType]valueType{
    key1: value1,
    key2: value2,
    // ...
}
// 使用 make() 函数创建一个空的 map
    myMap := make(map[string]int)

    // 或者直接声明并初始化 map
    myMap2 := map[string]string{
        "name":  "John",
        "age":   "30",
        "email": "john@example.com",
    }

   // 添加元素到 map
    myMap["apple"] = 10
    myMap["banana"] = 5
    myMap["orange"] = 8

    // 访问 map 中的元素
    fmt.Println("Number of apples:", myMap["apple"])
    fmt.Println("Number of oranges:", myMap["orange"])

    // 删除 map 中的元素
    delete(myMap, "banana")

    // 判断某个键是否存在于 map 中
    value, ok := myMap["grape"]
    if ok {
        fmt.Println("Number of grapes:", value)
    } else {
        fmt.Println("Grape not found.")
    }

    // 遍历 map
    for fruit, count := range myMap {
        fmt.Printf("Number of %s: %d\n", fruit, count)
    }

image-20230802183114762.png

遍历引用类型

for i,ele :=range slice{}   // 切片
for key,value :=range map{}//不保证遍历的顺序  map
for ele := range ch{} //遍历并取走管道里剩下的元素,一定要先close(ch)  channal
for range拿到的是数据的拷贝

结构体和接口

// 结构体
type User struct {    // 大写是 包外可见
ld  int //大写开头的为导出成员  
People //匿名成员,可实现“继承
enrollment time.Time
name,addr string //多个字段类型相同时可以简写到一行里
}

//接口
type Animalinterfacef{
    Say(int) (int,error)
}    

初始化一个实例

var u User//声明,会用相应类型的默认值初始化struct里的每一个字段
u =User{}//相应类型的默认值初始化struct里的每一个字段
u =&Userf//返回指针
u =User{id:3,name:"zcy"}//赋值初始化
u=User[4,100.0,time.Now(),"zcy","beijing”}//赋值初始化,可以不写字段,但需要跟结构体定义里的字段顺序一致

方法

我们习惯上把结构体的函数称之为方法

//可以把user理解为hello函数的参数,即hello(u user,man string)
func(u User) hello(man string){
	fmt.Println("hi" + man + ", my nameis"+u.name)
}
//函数里不需要访问user的成员,可以传匿名,甚至_也不传
func(_ User) think(man string){
	fmt.Println("hi"+ man +",do you know my name?")
}

func(u*User) grow(n int) {	//如果想修改成员变量,需要传struct的指针
    u.age+=n
}

Switch

switch {
    case add(5)>10:
    fmt.Println("right")
default:
    fmt.Println("wrong")
}

switch value := num.(type){//相当于在每个case内部申明了一个变量value。.(type)只能用在switch后面
    case  int://value已被转换为int类型
    fmt.Printf("number is int %dn", value)
case float64: //value已被转换为float64类型
    fmt.Printf("number is float64 %fn" value)
case byte,string://如果case后有多个类型,则value还是interface{}类型
    fmt.Printf("number is inerface %vn", value)
}

函数传参

传引用类型可以修改底层内存里的值

传数组和结构体会整体拷贝,性能低,且不影响实参。除非传指针

不定长参数

func variableengtharg(a int, other ...int) int {
    sum := a
    for _,ele:= range other {//不定长参数实际上是slice类型,也就是切片
    sum += ele
    }
    fmt.Printf("len%d cap %d\n",len(other),cap(other))
    return sum
}
variable_ength_arg(1)
variable_ength_arg(1,2,3,4)

panic

什么时候会发生panic

1.运行时错误会导致panic,比如数组越界、除0

2.程序自动调用panic(error)

panic会执行什么

1.逆序执行当前的goroutine的defer链(recover从这里开始介入)

2.打印错误信息和调用堆栈

3.调用exit(2)结束整个进程