Go语言学习笔记2019.11.26


函数

定义格式

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
阅读 2015 讨论 0 喜欢 0

抢先体验

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

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1