区块链 GO 函数

函数是基本的代码块,用于执行一个任务,是构成代码执行的逻辑结构。
在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句。

函数定义

每个go程序都是从名为main的package包的main()函数开始执行包的概念不是这里的重点,以后做单独说明。同时main()函数是无参数,无返回值的。

格式

func funcName(形参1 type[, 形参2 type...]) [([[返回变量1] type[, [返回变量2] type...]])] {
[return [返回变量1[, 返回变量2...]]]
}
a. 如果形参类型都一样,可以这样写: 形参1, 形参2 type, 同时返回变量也一样
b. 如果只有一个返回值或者无返回值, 可以去掉对应的()
c. 如果返回有返回值,该函数中最外层要有return语句
d. 返回语句(), 返回变量名可以省略
e. []表示可省略
f. 不支持默认参数

package main

import "fmt"

func printName(name1 string, name2 string) {
    fmt.Println("name1 = ", name1, "  ", "name2 = ", name2)
}

func main() {

    printName("张三", "李四")

}
输出为:
name1 = 张三     name2 = 李四 
package main

import "fmt"

// 如果有多个参数,并且参数类型一致,可以省略掉前面的参数的类型
func printName(name1, name2 string) {
    fmt.Printf("%T\t%T\n", name1, name2)//输出验证name1, name2的类型是否为string
    fmt.Println("name1 = ", name1, "  ", "name2 = ", name2)
}

func main() {
    // var a,b,c,d int;

    printName("张三", "李四")
}
输出为:
string  string
name1 = 张三     name2 = 李四 
作用域

在 Go 中,定义在函数外的变量是全局的,那些定义在函数内部的变量,对于函数来说是局部的。如果命名覆盖 — 一个局部变量与一个全局变量有相同的名字 — 在函数执行的时候,局部变量将覆盖全局变量。

返回值

函数的返回值可以是一个也可以是多个

package main

import "fmt"

// func关键字
// aAddB函数名
// a、b 参数
// int 返回值类型
//下面是几种返回值类型与返回值的写法:
func aAddB(a, b int) int {
    return a + b
}

// func aSubB(a, b int) int {
//  return a - b
// }

// func aSubB(a, b int) (int) {
//  return a - b
// }

// func aSubB(a, b int) (s int) {
//  s = a - b
//  return s
// }

// func aSubB(a, b int) (s int) {
//  s = a - b
//  return
// }

func aSubB(a, b int) (s int) {

    return a - b
}

func main() {
    num := aAddB(5, 6)
    fmt.Println(num)
    fmt.Println(aSubB(5, 6))
}

多个返回值
go支持多个返回值
如: for k, v := range array ...
a. 如果不想要某个返回值,可以用 "_" 代替,如 for _, v := range array...,不能直接写为这样 for , v :=range array...,但可以省略 v(值), 写为 for k := range array...
b. 如果普通函数返回n个值时,不能用少于n个变量去接收
c. 不能直接打印有多个返回值的函数调用结果
d. 如果定义了返回值的变量名,就可以省略 return 语句后面的返回列表

函数参数

函数定义时指出,函数定义时有参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。
但当调用函数,传递过来的变量就是函数的实参,函数可以通过两种方式来传递参数:

值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

变参

接受变参的函数是有着不定数量的参数的。其函数定义形式如下:

func funcname(arg ... type) { }

arg ... type 告诉 Go 这个函数接受不定数量的参数。注意,在函数体中,变量 arg 是一个type类型的 slice,可以使用 range 遍历,也可以将其作为实参全部或者部分传递给调用函数。

package main

import "fmt"

// 传的是一个slice,slice分片
func sortSlice(numbers []int) []int {
    fmt.Println(numbers)
//冒泡排序
    for j := 0; j < len(numbers)-1; j++ {
        for i := 0; i < len(numbers)-1-j; i++ {
            if numbers[i] > numbers[i+1] {
                temp := numbers[i]
                numbers[i] = numbers[i+1]
                numbers[i+1] = temp
            }
        }
    }

    return numbers
}

func main() {
    // 排序前
    numbers := []int{23, 45, 12, 56, 78, 89}

    // 排完序以后的numbers
    numbers = sortSlice(numbers)

    fmt.Println(numbers)

}

package main

import "fmt"

// 动态参数
func sortSlice(numbers ...int) []int {
    fmt.Println(numbers)
    //冒泡排序
    for j := 0; j < len(numbers)-1; j++ {
        for i := 0; i < len(numbers)-1-j; i++ {
            if numbers[i] > numbers[i+1] {
                temp := numbers[i]
                numbers[i] = numbers[i+1]
                numbers[i+1] = temp
            }
        }
    }

    return numbers
}

func main() {
    // 排序前
    numbers := []int{23, 45, 12, 56, 78, 89}

    // 排完序以后的numbers
    numbers = sortSlice(numbers...)

    fmt.Println(numbers)

}

函数作为值
package main

import "fmt"

// 内容:
// 函数本身也是一个类型
// 函数也有变量
// 函数也可以赋值

var a int = 9

// greating : 函数变量
// 函数值:
// func () {
//  fmt.Println("Hello World!")
// }

// 全局的函数的声明
func greating() {
    fmt.Println("Hello World!")
}

// func(int, int) int

// 判断函数类型的方法:
// 只需要把函数名和其他行参名字去掉,剩下的就是函数类型
func addAB(a int, b int) (s int) {
    return a + b
}

func aSubB(a, b int) int {
    return a - b
}

func main() {
    greating()
    // 函数赋值
    greating1 := greating

    greating1()
    // 打印类型
    fmt.Printf("%T \t %T\n", greating1, greating)
    /*
       Hello World!
       Hello World!
       func()    func()
    */

    fmt.Printf("%T\n", addAB)
}

匿名函数

匿名函数即没有函数名的函数,只能放在函数中,可以实现函数嵌套定义的功能。

package main

import "fmt"

func main() {
    // greating局部变量
    greating := func() {
        fmt.Println("Hello World!")
    }
    // 只有调用函数的时候,函数体里面的代码才会被执行
    greating()
    // 函数值,匿名函数
    func() {
        fmt.Println("函数值,匿名函数!")
    }()
}

返回值为函数
package main

import "fmt"

func main() {
    fmt.Println(printName("张三"))

    // 函数赋值
    name := printName
    fmt.Println(name("李四"))

    // 局部变量
    name1 := func(name string) string {
        return name
    }
    fmt.Println(name1("王五"))
    
    // 函数里面返回函数
    // func(string) string
    name2 := makeNameFunc()
    fmt.Printf("name2的类型为:%T\n", name2)
    fmt.Println(name2("赵六"))
}

// 返回值为函数
// 返回的函数的类型为func(string) string
//函数类型:func() func(string) string
func makeNameFunc() func(string) string {
    return func(name string) string {
        return name
    }
}

func printName(name string) string {
    return name
}

输出为:
张三
李四
王五
name2的类型为:func(string) string
赵六
匿名函数/闭包
varName := func() {...}
    varName() //调用匿名函数
    //匿名函数也可以作为一个返回值赋值给变量
    func func1(m int) func(int) int {
      return func2(n int) int {
        return m + n
      }
    }
    varName := func1(m) //func1(m)返回的结果就是func2函数
    varName(n)//就相当于下面这个函数
    func2(n int) int {
      return m + n//m在func1(m)已确定值
    }

example code list

import "fmt"

func main() {
  //5. 函数作为值/类型
  //匿名函数
  varFunc := testFunc
  varFunc()
  //闭包
  varFunc1 := closure(10)
  fmt.Println(varFunc1(20)); //30
  /**************************/
  /*运行结果:               */
  /*func as a var           */
  /*30                      */
  /**************************/
}

func testFunc() {
  fmt.Println("func as a var")
}

func closure(m int) func(int) int {
  return func(n int) int {
    return m + n
  }
}
回调函数

函数也可以作为另一个函数的参数,即回调函数。回调函数需要调用函数的形参格式和被调用函数原型相同。

package main

import "fmt"

// 函数类型:func ( []int, func ())
// 参数一类型:[]int
// 参数二:func ([]int)
func method(array []int, callback func([]int)) {
    callback(array)
}

func main() {

    a := []int{2, 5, 1, 67, 89}
    callback := func(array []int) {
        fmt.Println(array)
    }
    fmt.Println("========")
    method(a, callback)
}

递归的使用
package main

import "fmt"

// 10的阶乘
// 10*9*8*..*2*1

// 10 * 9*jieceng(8)

func jieceng(num int) int {
    if num == 1 {
        return 1
    }
    return num * jieceng(num-1)
}

func main() {
    num := jieceng(10)
    fmt.Println(num)
}

defer

defer声明的语句会存在类型于栈的结构中,先进后出,在函数快执行完毕(或者return)时执行,类型于析构函数
格式
defer 表达式|函数
常用于文件关闭等操作,还有重要的 recover 函数

package main

import "fmt"

func printWord(s string) {
    fmt.Println(s)
}

func main() {
    defer printWord("World!")
    printWord("Hello!")
    defer printWord("Wecome!")
    printWord("To Beijing!")
    defer printWord("123!")
    printWord("456!")
}

输出为:
Hello!
To Beijing!
456!
123!
Wecome!
World!
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容