Go语言学习笔记2019.11.26


函数

定义格式

0秒抢红包:这种创作,不使用任何乐器,纯人声。

func FuncName(/*参数列表*/) (o1 type1,o2 type2/*返回类型*/) {
    // 函数体
    return v1,v2 //  返回多个值
}

自定义函数

无参数无返回值函数

func MyFunc(){
    a := 666
    fmt.Println("a = ",a)
}
func main(){
    //无参返回值函数调用:函数名()
    MyFunc()
}

有参无返回值函数

func MyFunc(a int ){
    fmt.Println("a = ",a)
}
func MyFunc02(a int , b int){
    fmt.Print("a = %d, b = %d\n " ,a ,b )
}
func main(){
    //有参返回值函数调用:函数名( 所需参数 )
    MyFunc(111)
    MyFunc02(555,666)
}

不定参数列表

  1. 不定参数,一定(只能)放在形参中最后一个元素
  2. 固定参数一定要传参,不定参数可根据需求灵活传参
// 类似...int 这样的类型,是不定参数类型
func MyFunc(args ...int){
    for i := 0; i<len(args) ; i++ {
        fmt.Printf("args[%d] = %d\n" , i, args[i])
    }
    for i, data := range args  {
        fmt.Printf("args[%d] = %d\n" , i, data)
    }
}
func main(){
    // 有参返回值函数调用:函数名( 所需参数 )
    // 传递的实参可以是0个或多个
    MyFunc(1,2,3)
}

不定参数传递

func test(args ...int){
    // 全部传递
    myfunc(args...);
    // 只传后两个
    myfunc(args[2:]...) // 从args[2]开始(包括本身),把后面所有元素传递过去
    myfunc(args[:2]...) // 把从args[0]到args[2]号元素传递过去(不包括2)
}

一个返回值函数

有返回值的函数需要通过return中断函数,通过return返回
也可以提前给返回值起一个变量名,然后在函数中赋值返回
有返回值的函数,必须有return

func myfunc01() int {
    return 666
}
// 给返回值起一个变量名,go语言推荐写法
func myfun02 (result int) {
    return 666
}
// 或者下面这种形式 --- 常用写法
func myfunc03 (result int) {
    result = 666
    return
}

func main(){
    var a int
    a = myfunc01()
    b := myfunc01()
}

多个返回值

func myfunc01() (int, int, int) {
    return 1,2,3
}
// go语言官方推荐写法
func myfunc02() (a int, b int, c int) {
    a, b, c = 111, 222,333
    return
}

func main() {
    // 函数调用
    a,b,c := myfunc01()
}

有参有返回值

func MaxAndMin(a,b int) (max ,min int){
 if a>b{
     max = a
     min = b
 }else{
     max = b
     min = a
 }
 return
}
func main() {
    max, min := MaxAndMin(10, 20)
}

递归函数

函数类型

在Go语言中,函数也是一种数据类型。也可以通过type给一个函数类型起名。
Go语言的“多态”实现方式。
多态:多种形态,调用同一个接口,可以实现不同的表现
适用于先有想法,后面再实现功能

type func(int , int) int // 没有函数名字,也没有{}
type FuncTyper func(int , int) int 

func main(){
    // 声明一个函数类型的变量,变量名叫fTest
    var fTest FuncType
    fTest = Add // 是变量就可以赋值
    result = fTest(10, 20) // 等价于Add(10, 20)
    
    // 也可以继续变化
    fTest = minus
    result = fTest(10, 5) // 等价于minus(10, 5)
}

回调函数

函数有一个参数是函数类型,这个函数就是一个回调函数。
优点:方便拓展、可以在函数体内调用暂无实现的方法。

// 实现一个可以进行四则运算的计算器
type FuncType func(int , int) int
func Calc(a, b int, fTest FuncType) (result int) {
    result = fTest(a, b) // 这个函数还没有实现,(先定义调用,后实现)
    return
}
func main(){
    a := Calc(1, 1, Add)
}

匿名函数与闭包

func main() {
    a := 10
    str := "mike"
    
    // 匿名函数,没有函数名字;此处为函数定义
    f1 := func() {
        // 函数内形成闭包,可以调用外面的变量
        fmt.Println("a = ", a )
        fmt.Println("str = ", str )
    }
    f1()
    
    // 定义匿名函数,同时调用
    func() {
    fmt.Printf("aaa")
    } () // 后面的()代表调用此匿名函数
    
    // 匿名函数有参、有返回值、自动调用
    x , y := func(i, j int) ( max, min int) {
        if i>j {
            max = i
            min = j
        }else{
            max = j
            min = i
        }
        return 
    }(10, 20)
}

闭包捕获外部变量的特点

闭包是以引用方式捕获外部变量,包内修改变量,包外也同步修改

闭包的特点

闭包不关心捕获了的变量和常量是否已超出作用域,只要有闭包还在使用,这些变量就会一直存在。

// 函数的返回值是一个匿名函数,返回一个函数类型
func test02() func() int {
    var x int // 没有初始化,默认值为0
    return func() int {
        x++
        return x * x
    }
}

func main() {
// test02的返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数
    f := test02()
    f() // 1
    f() // 4
    f() // 9
    f() // 16
}

延迟调用 defer

defer作用

延迟语句执行顺序,函数结束前,最后调用 defer定义的内容。

多个defer执行顺序

先defer的,后执行。先进后出。
若某一 defer 函数发生错误,其他 defer 语句正常执行。

func test(x int){
    result := 100/x
    return result
}
fun main() {
    fmp.Println("aaaa")
    fmp.Println("bbb")
    test(0)  // 调用一个函数,导致内存出问题
    fmp.Println("ccc")
}

defer结合使用

func main() {
    a := 10
    b := 20
    
    defer func() {
        fmt.Printf("a= %d, b= %d\n",a,b)
    } () // 打印出来结果为111,222
    
    a = 111
    b = 222
    fmt.Printf("外部 a= %d, b= %d\n",a,b)
}
func main() {
    a := 10
    b := 20
    
    defer func(a,b int) {
        fmt.Printf("a= %d, b= %d\n",a,b)
    } (a, b) // 打印出来结果为10,20,调用时,已经先传了当下的参数,后面再修改与此处无关
    
    a = 111
    b = 222
    fmt.Printf("外部 a= %d, b= %d\n",a,b)
}

获取命令行参数

func main() {
    list := os.Args
    n := len(list)
    fmt.Println("n = ",n)
    for i := 0;i<n:i++{
        fmt.Printf("list[%d] = %s\n",i,list[i])
    }
    
    for i,data := range list{
        fmt.Printf("list[%d] = %s\n",i,data)
    }
}

作用域

作用域:变量的作用范围。

局部变量

定义在{ }内的变量,只在{ }内有效。
执行到定义变量时,定义语句才会分配空间,离开作用域时,局部变量自动释放

全局变量

定义在函数外部的变量,全局变量在任何地方都能使用。

不同作用域同名变量

就近原则。

工程管理

工作区

工作区介绍

Go代码必须要放在工作区中,工作区其实就是一个对应于特定工程的目录,它应包含3个子目录:src、pkg和bin目录。

  1. src:以代码包形式组织并保存Go源码文件
  2. pkg目录:用于存放经由go install命令构建安装后的代码包(包含Go库源码文件)的".a"归档文件。
  3. bin目录:与pkg目录类似,在通过go install命令构建安装后,保存由Go命令源码文件生成的可执行文件。

目录src用于包含所有的源代码,是Go命令行工具的一个强制规则,而pkg和bin目录不用手动创建,Go命令行工具会自动创建。

GOPATH设置

为了能够构建这个工程,需要先把所需工程的根目录加入到环境GOPATH中。

本文发表于2019年11月20日 21:20
阅读 41 讨论 0 喜欢 0

讨论

周娱

君子和而不同
按照自己的方式,去度过人生

8000 3143834
抢先体验

扫码体验
趣味小程序
文字表情生成器

加入组织

扫码添加周娱微信
备注“加入组织”
邀请进开发群

闪念胶囊

这个世界上,别人只会看你现在的样子而不是以后的样子。你以后的样子只有自己才相信。如果没有执行力,一切都是虚妄。

对普通人来说,人和人相处其实最重要的是感觉。感觉不好,你说什么都没用,怎么解释都没用,越说越错,反正最后不好的锅都往你身上扣。所谓“说你行你就行,不行也行。说你不行,你就不行,行也不行”就是这个意思。狼要吃人根本不需要理由,你也同样叫不醒装睡的人。遇到这种情况,早点闪人才是上策。不过大部分人的问题是没有闪人的心态,能力,和资源。

考985不牛逼,考上才牛逼。创业不牛逼,创业成功才牛逼。这个社会上很多人把目标当成牛逼的资本,牛逼哄哄的,死活不听劝,然后做的一塌糊涂,给别人添麻烦,让别人帮他料理后事,对此只能呵呵。

当你尝到用生气解决问题的甜头后,你就懒得再用其他方式了。你却忽略了,生气是鸩毒啊,剂量用够了,你的关系也玩完了。

年轻的时候你只搞事业不谈恋爱,等你事业有成了,钱相对自由了,你可能已经没有荷尔蒙了。

如果你经常雇佣比你矮小的人,将来我们就会变成矮人国,变成一家侏儒公司。相反,如果你每次都雇用比你高大的人,日后我们必能成为一家巨人公司。

如果一个人有充裕的时间去完成一项工作,那么他就会放慢节奏或者增加其他不必要的工作,直到花光所有的时间。

天空不是人类休息的地方,人类应该去亲近海洋。

一个人的正直程度,取决于他肯为原则付出的牺牲。

Copyright ? 2016 - 2018 Cion.
All Rights Reserved.
备案:鲁ICP备16007319号.