GO语言学习笔记---基础知识篇|青训营笔记

122 阅读3分钟

“这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

ps:本人的笔记多以代码的形式呈现,可以在注释中查看到详细的解释

基础知识

变量定义

变量类型:字符串(string,内置型,可以直接+,=等),整数(int32),浮点型(float64(默认)||float32),布尔型,复数类型(complex128),字符类型(默认rune),数组,切片,map,指针类型,错误类型(error类型,默认值是nil)

变量以及变量声明方式

单个变量声明:

var name=value          //该方法会自动判断变量的类型
var name type = value               //显式地写出变量的类型
var name = type(value)                //通过显式类型转换赋值
name := value           //短变量声明方式,建议在局部变量定义并且需要指定初始值的时候使用
var name type             //定义未初始化的变量,一般用于定义暂时不需要初始化的局部变量
const name (type) = value    //定义常量,没有类型,根据变量的的值进行判断,也可以加类型,常量不能使用 :=来定义
err := nil

变量块声明:

var{
    name1 type = value1
    name2 type = value2
    ....
}

变量行声明:

var name1, name2, name3 =value1, value2, value3
name1, name2, name3 := value1, value2, value3
var{          //变量行的定义块
name1, name2, name3 =value1, value2, value3
name4, name5, name6 =value1, value2, value3
}

条件语句

if-else:可以类比于传统的C/C++中的if-else

if value1 {           //单条件if
    语句
}else{
    语句
}
​
​
if 语句1; value2{                  //在if前面添加语句,先执行语句然后再执行判断条件value
    
}else if value3{
    
}
​
​
if 语句2; value1 && value2{           //一个执行语句两个判断条件
    
}

循环语句

for:与传统的C/C++中的for循环也是类似的,for中的三个语句都是可以省略的,此时就相当于while(true)

for i:=0; i<n; i++{           //常规写法
    语句
}
 
​
//变形写法
i:=1
for i<n{
    语句
    i++
}
​
//死循环
for{
    语句
}
​

for...range...:每次获取一对数,下标和数值,for只能通过下表获取元素,可以遍历切片、数组、字符串、Map、Channel

for index, value:=range arrayTest{         //在这里需要注意,如果直接修改value的值是不能够修改对应array Test的值的,因为是copy过来的,必须通过下标访问
    语句
}

switch分支结构

所有的case语句后面的常量值都不允许有重复,否则就会报错,并且在switch之后可以接需要执行的句子,然后再接分支变量,使用分号隔开即可 case 1: 语句

switch (语句;)name{        //一般的switch语句,name可以是任何变量
    case value1, value2, value3 : 语句           //case多种情况进行同样的操作
    case 3: 语句
    case 4: 语句
    default: 语句
}
​
//可以用于多个if--else的替代
switch (value){                  //()内的value是可以省略的,此时则会判断case语句中的条件,一旦为真就会执行
    case condition1 && condition2 ||....: 语句1
    case  ....
    case  .... 
    fallthrough              //不执行默认的跳出switch操作,直接执行下一个case(此时就不会判断case了,而是直接执行语句)
    case ....
}
​

GO中的break与continue

GO中的break语句和continue语句基本用法可以参考java中的用法,既能退出循环又能跳到指定位置

label1:
for{
    switch value{
        if value<0 {
            break;             //跳出switch循环
        }
        case 1: break label1         //直接跳到label,相当于goto
    }
}

数组

数组在go语言中用的比较少,主要原因还是在于数组的长度固定,不太适合数据的动态交互

var name[length]type            //定义未初始化的数组
name :=[...]{values}          //定义数组并且初始化
name[1]=value                 //使用下标修改数组


//遍历数组
for i:=0; i<len(array); i++{            //一般的for遍历
   ...
}

for i, value := range array{        //使用range遍历
    ...
}

切片

定义:任意长度的数组,可以更改长度,可以类比于STL中的vector函数,切片也可以遍历,方式和数组一样

切片的定义和初始化

var name[]type            //定义切片
var number=make([]type,length)      //定义初始长度为length的切片
name :=make([]type, length)           //同上
arr := [...]type{values}         //使用数组初始化

切片的常用方法

n= cap(number)         //求出切片的容量
name=append(name, value)       //在切片的最后插入元素并且返回新的切片
copy(number, name)   //将name中的值复制到number当中
//切片的切片操作
fmt.Println(name[value1: value2])    //输出下标从value1到value2的全部数据,遵循取左不取右的原则,不会输出value2下表的值,省略value1或者value2的时候会直接从开头开始取或者一直取到结尾
number2 := name[0:3]           //切片赋值,number2成为一个新的切片
s = number ;           //赋值操作,此时对s进行的操作都会与number同步

从切片中删除元素

公式:要从切片a中删除索引为index的元素,则执行操作append(a[:index],a[index+1:])

s :=[]int{23,43,23,43,53,43,34,54}
s = append(s[:2],s[3:])              //删除元素23

map

可以参考python中的字典,两者具有类似性

声明方式汇总

name :=make{map[keyvalue]type}           //定义一个关键字为keyvalue,类型为type的map
var name map[keyvalue]valuetype   

map的基本数据操作

name[keyvalue] = value              //修改操作
value, jude := map[keyvalue]           //判断keyvalue的键值存不存在,存在jude为true

map的遍历

for key := range name{         //遍历key
    .....
}

for key, value := range name{           //遍历关键字和值
    ......
}

指针

指针在go中的主要用途就是实现函数对外部变量的修改,即类似于C++中的引用变量,在这里需要记住,go中的赋值操作与copy操作是不一样的,赋值会指向同一地址,改变一个会改变所有

number := 3

func function(name *int)(){
    name+=1
}

function(&number)             
fmt.Println(numer)             //输出4var ptr[3] *int          //定义指向数组的指针
a :=[]int{1,2,3}
for i :=0 ;i < 3; i++{
    ptr[i] = &a[i]
}
fmt.Println(ptr)                  //输出1 2 3

结构体

结构体类似于C/C++中的结构体,但是赋初值的方式略有不同,ps:结构体作为函数参数的时候也会有指针和非指针两种用法

type name struct{
	name1 type
    name2 type
    name3 type
}
//初始化1(部分成员初始化)
a := name{name1:value1, name2:value2}               //name3没有传入,那么就会直接设置默认空值
//初始化2(所有成员初始化
a := name{value1, value2, value3}
//初始化3(使用new关键字创建结构体指针)
var a = new(name)

a.name1 = value3               //通过.运算符访问结构体变量

匿名结构体

不给结构体实际的变量名即为匿名结构体

var name struct{
    ...
}
name.value = value           //临时使用结构体,故而可以不用对结构体起名字(a := name)

结构体方法

类似于类方法,也可以通过(.)运算符进行调用

type name struct{
    name1 type
    name2 type
}

func (p name)functionname(){         //定义结构体方法,如果第一个括号是p *name那么方法内就可以直接修改结构体的值
    p.name1=....
}

a :=name{name1: value1}
a.functionname()                //调用结构体方法

错误处理方式

go中对错误的处理方式是对目标语句进行判断,如果输出了nil那么就对nil进行判断

func function ()(number int, err error){
    err, value :=f(3,4)
    if err==nil{
        fmt.print(err)
        return
    }
    	
}

打印

对于不同类型的变量,go统一使用%v表示,不同的输出要求有不同的输出格式符

fmt.Printf("%v", name)         //打印值
fmt.Printf("%+v", name)         //打印变量名:值
fmt.Printf("%#v", name)        //打印变量的类型 变量名:值       
fmt.Printf("%.nf", name)           //控制打印位数

时间处理

使用import time中的各种方法

import{
    "time"
    "fmt"
}
now := time.now()           //获取当前时间
fmt.Printf(now)
now.format("2006-01-02 15:23:09")                  //格式化成标准样式
fmt.Printf(now.Unix)          //获取时间冲

字符串转数字

依靠strconv中的方法进行转换

import{
    "fmt"
    "strconv"
}
n, _ :=strconv.ParstInt("目标字符串", 字符串的进制(0代表自己判断, 精度)              //字符串转数字
fmt.Printf(n)
n, _ := strconv.Atoi("目标数字")            //数字转字符串

GO--函数

函数的特性

  • 函数分为:普通函数,匿名函数,方法
  • go当中不允许重载函数(但是可以重写)
  • 除了匿名函数以外,所有的函数都不能互相嵌套
  • 函数是一个值,可以赋值给变量,让这个变量也变成函数
  • 函数可以作为函数的参数
  • 函数可以作为函数的返回值
  • 函数的参数可以没有名称
  • 函数可以返回多个值
  • 在函数中的返回值是实现定义好的,可以直接再函数体中使用

函数的定义和用以及返回值

函数的定义:

func functionname (valuename1 type, valuename2 type) [returnvalue1 type, returnvalue type]{
    //函数体
}

函数的调用:

ans1, ans2 = functionnaem(value1, value2)

函数的返回值:

func function()(ans int){
    name : = "字节跳动"
    age := 99999
    net =int32(87)
    return net             		 //返回单个参数    
}

func function()(ans int, ans2 string){
    name : = "字节跳动"
    age := 99999
    net =int32(87)
    return net, name             		 //返回多个参数    
}

func function()(ans int, ans1 string){
     name : = "字节跳动"
    age := 99999
    net =int32(87)
    return        					//没有指定返回的参数,并且函数体中也没有使用到返回值变量ans和ans1,所以没有返回值
}

func function()(ans int, ans1 string){
    ans1 : = "字节跳动"
    ans := 99999
    net =int32(87)
    return 						//直接返回ans1和ans因为函数中使用这两个参数并且对其进行了初始化
}


func add(x, y int)int{
    return x+y
}

func sub(x, y int)int{
    return x*y
}

func call(s string)func(int, int)int{
    switch s{
        case "+":
        return add                 //函数作为返回参数
        case "*":
        retuern sub
        default:
        return nil             //返回错误(error变量的默认值)
    }
}

函数的参数

map、slice、interface、channel这些数据类型本身就是指针类型的,所以就算是作为参数拷贝也会影响到原本的值,即相当于引用变量

package main
import {
    "fmt"
}
//切片等作为参数
func function( name[] int){               //切片作为参数
    
}
//长参数
func function(ans int, ans1 string, ans3...int){					//最后一个为可变参数,数量不确定
    for _, v := range ans3{                    //对其中的元素进行访问
        
    }
    ans[2] = 90             //直接使用下标访问,但是要注意越界
}
//函数作为参数
func function(name string)(){
    fmt.Println(name)
}

func function1(name string, f fun(string)){          //函数作为参数
    f(name)
}

函数类型的变量

函数的变量类型可以是:一般参数,结构体,指针,函数,结构体指针等等

package main
 
import "fmt"
 
type fun func(int, int) int                //定义一个函数类型的变量
 
func sum(a int, b int) int {
    return a + b
}
 
func max(a int, b int) int {
    if a > b {
        return a
    } else {
        return b
    }
}
 
func main() {
    var f fun
    f = sum                      //函数作为变量赋值
    s := f(1, 2)
    fmt.Printf("s: %v\n", s)
    f = max
    m := f(3, 4)
    fmt.Printf("m: %v\n", m)
}

匿名函数

go语言函数不可以嵌套,但是匿名函数可以嵌套,在函数内部可以定义匿名函数来进行一些处理和操作,可以参考一下java中的匿名内部类

//语法格式
func(参数列表)(返回值)               //参数返回值都可省略
​
​
func main(){
    a :=func(a int, b int)int{            //定义匿名函数
        if a>b{
            return a
        }else{
            return b
        }
    }
    
    i := max(1,2)
    fmt.Printf(i)
}

本次学习的感受

学习完相应的内容之后,我对go语言有了更加深入的了解,其实go语言并没有我想象的那么难,他更像是C++,AVA和python的结合体,基本的底层原理像if else for等等基本是与C++类似,而像对数据类型的高级操作,例如切片格式化,等等就与python中的数据处理方式类似,而对于变量的赋值指针以及copy函数的处理方式,则与JAVA中类似,够语言就像是一个容器集合的各种常用语言的优点。这其中,最让我震惊的当属switch语句,我从来没有想过switch语句原来可以巧妙的使用,并且来代替连续的嵌套if语句,使整个项目以及代码更具有可观性和可维护性,这是我第一次接触go语言,也希望之后的学习中能够对go语言有更深刻的理解和感悟,争取在青训营期间收获自己想要的东西

参考文献

[]((6条消息) Go语言自学系列 | 汇总_COCOgsta的博客-CSDN博客)