Go语言学习流程记录--从环境搭建--变量相关--流程控制语句

环境搭建

  1. mac下,下载go安装包直接安装
  2. linux下,下载go源码自行编译或直接下载对应版本的预编译版本
  3. 安装VScode 以及 Go 插件
  4. 设置 GO111MODULE="on", 设置 GOPROXY="https://goproxy.io" => 用于代理安装依赖

 

变量

申明:

申明变量的格式为 var name type ,举个例子,想申明一个变量为年龄,则使用 var age int 

 

初始化:

在Go中,每申明一个变量时,会被初始化赋值为该类型的基础值,例如,int 则为 0,float 则为 0.0,bool 为 false, string 为 "",指针(函数、切片)为 nil 等。

一半的初始化写法不同语言都基本一致: var age int = 18 , 其实,这里可以采用类似于动态语言的写法,不申明变量类型,形如 var age = 18 ,但实际上是静态的,此处Go会判断右侧值得基本类型,并给左侧变量确定基本类型。

同时,在Go中,可以在申明时直接初始化,格式为 age := 18 ,这个的好处就是简洁。

 

赋值:

初始赋值在初始化中已经说过了,另外就是在赋值语句中,将赋值号右侧表达式的返回值赋值给左侧变量。大体而言是这样的 age = 19

在Go语言中,表达式支持返回多个值,因此,赋值语句的左侧也支持放多个变量,格式为 name, age := "zhangsan", 19 , 多重赋值的用处,在错误处理机制和条件判断时非常有用,可以人为约定返回的第一个值为错误码,只有错误码为空时,才能继续执行后续的代码。

 

匿名变量:

由于可以多重赋值,因此在接收表达式的值时,就必须有一个变量去接收所赋的值,例如 neednot, name := "xxx", "long" , 但实际我们在后面的代码中,不会用到前面传回的值,而 go 的语法检查,又不允许我们初始化一个我们不会使用的变量,因此,这个 匿名变量 就派上用处了,只需要用一个特定的变量名去接收,就可以不去使用这个变量,这个变量名为 _ ,也就是可以这样: _, name = "xxx", "long"

 

作用域:

变量都有其生效的范围,变量的作用域可以分为3种,其一, 局部变量 ,也就是在函数体内的变量,举个例子:

package main

import "fmt"

func main () {
    // 申明并初始化一个 string 类型的局部变量 name
    var name string = "long"
    fmt.Println("my name is ", name) // my name is long
}

在这个例子中,name 就是一个局部变量,仅有在main函数中,才能使用这个变量。

ps: 这里的 “在函数中”,指的是“在函数中定义的”,有些编程语言的变量是动态的,只有在运行时才能判断是否存在该变量,因此有些时候可以在申明函数时不申明该变量,而是在实际运行时才会有,例如 shell 以及 python, 拿python举个例子:

def myfunc () {
    print(myname) # longalong
}

if __name__ == "__main__":
    myname = "longalong"
    myfunc()

如果按照在“函数定义处确定变量”这个规则,那么 myfunc 中的 myname 变量则未定义,但实际,这里会输出 “longalong”。

需要注意的是,Go 和大多数语言一样,局部变量的范围为 “在函数体定义的地方”。

 

除了局部变量,还有一个叫做 全局变量 ,顾名思义,就是在全局中申明的变量。举个例子:

package main

import "fmt"

var name string = "longalong"

func main () {
    fmt.Println("my name is : ", name) // longalong
}

虽然叫做 全局变量,但其实和局部变量是大概一个意思,只是之前的 局部 指的是 函数体 ,而这里的 全局 指的是 当前文件

 

除了上述两者,还有一个比较特殊的变量,叫做 形参变量 ,它所对应的范围,和局部变量一样,都是函数体内,大致可以理解成,传形参时,Go语言主动申明了一个局部变量去接收这个参数,举个例子:

package main

import "fmt"

func main () {
    var nameInMain string = "longalong"
    
    myfunc(nameInMain)
}

func myfunc (name string) {
    fmt.Println("name in myfunc is : ", name) // longalong
}

这里有一点值得说明的,那就是:在 Go 中,所有的传参都是传的 “形参”,没有在一些语言中的 传值 与 传址 之分(例如 vb)。但这并不意味着所有传入函数的参数,都不会影响到原来的参数,因为,在Go中,有“指针”这个概念,因此,若传的是指针,传入函数时,传的是 “指针所指地址的形参”,因此,在函数内部改变了该地址的值时,函数以外是会受到影响的。举个例子:

package main

import "fmt"

func main () {
    name := "longalong"
    
    fmt.Println("before change : ", name) // longalong
    
    changeName(name)

    fmt.Println("after change : ", name) // longalong
}

func changeName (name string) {
    name = "mylong"

    fmt.Println("name in changeName : ", name) // mylong
}

可以发现,传入的基本类型不受影响。

package main

import "fmt"

func main() {
    oriArr := [3]string{"long", "long2", "longalong3"}

    fmt.Println("before change : ", oriArr) // [long, long2, longalong3]

    changeArr(&oriArr)

    fmt.Println("after change : ", oriArr) // [ahahahaha, long2, longalong3]
}

func changeArr(arr *[3]string) {
    arr[0] = "ahahahaha"
}

可以发现,传入指针后,原来的变量发生了改变。

 

类型

在了解了 变量 之后,下一步就是理解 类型 , Go是一门强类型语言,也就是和 js 不同,所有的类型均是确定的,需要明确申明。ps:需要说明一下,动态类型和静态类型相对应,强类型和弱类型相对应,前者指的是“是否需要明确申明变量的类型”,后者指的是“是否可以隐式改变变量类型”,js是弱类型也是动态类型,而python仅是动态类型,是强类型。

因此,我们需要非常清楚地认识Go语言中的类型。

一般来说,几乎所有的语言都会分为两种类型,其一 基础类型 ,其二 复杂类型 ,在基础类型中,基本都会包括: 数字类型字符串类型bool类型  ,在复杂类型中,基本都会有: 数组类型字典类型字节类型。 若语言支持指针,则基础类型还包括 指针类型 。 ps:在传统js中,没有 字节类型 ,取而代之的是用对象数组进行模拟(例如 new ArrayBuffer(8)),在nodejs中,则提供了 Buffer 类。

 

因此,我们在申明一个变量时,就得确定清楚,我们需要一个什么样的变量,例如,我们需要一个存放名字的变量,则需要 var name string 这样的方式;又如,我们需要一个存放金额的变量,则需要 var amount float64 这样的方式;再如,我们需要存放一个星期中我们每天写代码的时长,则可以 var codingTimes [7]float32 = [7]float32{}

 

特殊的:

在Go中,有一种特殊的类型 复数 ,这是数学中的概念,除了在一些科学计算方面会使用,一般是用不到的。

 

在Go中,主要有这些类型:

  1. bool类型。 var isSuccess bool = true 
  2. 数字类型。 var age uint8 = 18 var amount float64 = 121.221 
  3. 字符串类型。 var title string = "this is title" 
  4. 指针类型。 intVal := 8; var ptr *int = &intVal 
  5. 数组类型。 var arr [3]int = [3]int{2, 21, 32} 
  6. 切片类型。
  7. 结构体类型。
  8. 字典类型。
  9. 接口类型。
  10. 通道类型。
  11. 函数类型。

 

运算符

运算符在程序中起着操作变量以及表达式值得作用,所以,实际上,所有值的变换规则,都是有运算符来决定的。

一半来说,编程语言都会有的运算符类型:

  1. 算数运算符。 数字的各种运算,四则运算、取余、取整、自增、自减。
  2. 关系运算符。 数字键的比较。 大于、小于、等于、不等于、不大于、不小于。
  3. 逻辑运算符。 bool类型的关系。 与、或、非、异或。
  4. 位运算符。 对于每一位进行的逻辑运算,然后再汇总。
  5. 赋值运算符。 各种类型的赋值。直接赋值、增加赋值、减少赋值等算数运算或位运算后赋值。
  6. 三目运算符。 简化版的if判断。(Go当中没有)
  7. 字符串拼接运算符。 字符串拼接,一半为 + , php中为 . , 也有不需要的,例如 python。
  8. 取值与取地址运算符。 * 取值,&取地址。

 

流程控制语句

流程控制语句是用来控制程序的执行结构的,也就是说,程序的执行逻辑,是由这类语句控制的。流程控制,有三种,顺序结构 分支结构 循环结构

分支结构

if语句

if语句是最基础的分支结构控制语句,根据判断条件,可以形成两个路径。举个例子:

package main

import "fmt"

func main () {
    isSuccess := true
    if isSuccess {
        fmt.Println("条件为真") // 条件为真
    } else {
        fmt.Println("条件为假")
    }
}

 

其实,在Go语言中,if语句是有隐藏的用法的,也就是在 if 的条件判断之前,可以执行一句代码,因此,很多时候可以在第一步执行一个函数,然后根据返回情况决定下一步的操作,举个例子:

package main

import "fmt"

func main () {
    if result := doSomething(); result {
        fmt.Println("操作成功")
    } else {
        fmt.Println("操作失败")
    }
}

func doSomething () bool {
    isSuccess := true

    return isSuccess
}

很多时候,上面这种结构用来判断一个函数是否执行无误,也就是看返回是否有 err 来判断是否继续执行。

 

switch语句

几乎在所有的编程语言中,都只有这两种分支结构语句,if 用来做两条分支的分流,switch 用来做多种分支的分流。

举个例子:

package main 

import "fmt"

func main () {
    days := [7]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}

    today := weekdays[1]
    
    switch today {
        case "Mon":
            fmt.Println("today is monday")
        case "Tue":
            fmt.Println("today is tuesday")
        case "Wed":
            fmt.Println("today is wednesday")
        case "Thu":
            fmt.Println("today is thusday")
        case "Fri":
            fmt.Println("today is friday")
        case "Sat", "Sun":
            fmt.Println("today is not weekday, ahhhhhh")
        default:
            fmt.Println("you must be kidding, no such a day !")
    }
}

其实,case后的这块儿内容,可以是逗号分隔的多个目标,也可以是一个表达式。

值得注意的是,有些语言的 case ,其实不是具有独占性的,例如 c 、js等,这意味着他们在进行了第一个case匹配后,若没有遇到 break、continue、return、goto 等关键词时,是会继续进行下一个 case 的匹配的,而在Go中,默认是仅进行一次匹配的,若希望继续向下匹配case,需要使用 fallthrough 关键词。

 

循环结构

计算机的强大之处,其一就在于能够重复执行大量的运算逻辑,体现在编程语言上,就是循环结构。

在各类编程语言中,几乎都有两类循环控制语句,一类是 for 循环,另一类的 while 循环。而在 Go 语言中,是没有 while 循环的,因为 for 循环能搞定一切。举个例子:

package main

import "fmt"

func main () {
    for round := 1; round <= 10; round++ {
        fmt.Println("in round ", round)
    }
    
    round2 := 1
    for ; round2 <= 10; round2++ {
        fmt.Println("round2 in round : ", round2)
    }
    
    round3 := 1
    for round3 <= 10 {
        fmt.Println("round3 in round : ", round3)
        round3++
    }
    
    round4 := 1
    for {
        if round4 > 10 {
            break
        }
        fmt.Println("round4 in round : ", round4)
        round4++
    }
   
    fmt.Println("finally get out of for loop")
}

这里面的三个语句块,可以进行很多的省略,例如 round := 1 其实可以是放在外面的,for 语句中可以直接空着; round++ 是可以放在循环体的最后的,for 语句中也是可以直接空着的; 若第一句和第三句均空着的话,那么可以直接省略前后两个分号; 如果三句均为空着的话,那么完全可以不写分号,这表示为一个无限循环语句,或者是一个在程序块内判断是否结束循环,然后用break、goto去控制何时结束循环。

 

循环控制语句中的另外两个关键字 breakcontinue ,这两者的用法和其他语言的用法一样。

 

迭代器

在各类语言中,都有可迭代对象,例如 数组、切片、字典、字符串等等,遍历这些可迭代对象是非常常见的操作,因此,需要有支持迭代的语句。在Go语言中,这个迭代语句为 for range , 举个例子:

package main 

import "fmt"

func main () {
    loopTar := [...]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
    for key, val := range loopTar {
        fmt.Println("key is :", key, "  value is : ", val)
    }
}

这是一个数组的迭代,可以迭代的类型有很多,例如 切片、字符串、字典、通道(在Go语言中独有的),这里再举个字典的迭代例子:

package main

import "fmt"

func main () {
    loopTar := map[string]string {
        "Monday": "星期一",
        "Tuesday": "星期二",
        "Wednesday": "星期三",
        "Thusday": "星期四",
        "Friday": "星期五",
    }
    
    for key, val := range loopTar {
        fmt.Println("today is : ", key, "  今天是 : ", val)
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iamlongalong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值