化整为零优化重用,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang函数的定义和使用EP07

简介: 函数是基于功能或者逻辑进行聚合的可复用的代码块。将一些复杂的、冗长的代码抽离封装成多个代码片段,即函数,有助于提高代码逻辑的可读性和可维护性。不同于Python,由于 Go lang是编译型语言,编译之后再运行,所以函数的定义顺序无关痛痒。

函数是基于功能或者逻辑进行聚合的可复用的代码块。将一些复杂的、冗长的代码抽离封装成多个代码片段,即函数,有助于提高代码逻辑的可读性和可维护性。不同于Python,由于 Go lang是编译型语言,编译之后再运行,所以函数的定义顺序无关痛痒。

函数声明

在 Go lang里,函数声明语法如下:

func function_name(parameter_list) (result_list) {  
    //函数逻辑  
}

这里使用function的简写形式 func关键词,后面依次接 function\_name(函数名) , parameter\_list(参数列表) , result\_list(返回值列表)以及函数体 。

parameter\_list(参数列表)成员:函数的参数名以及参数类型,这些参数作为局部变量,其值由参数调用者提供,函数中的参数列表和返回值并非是必须的。

result\_list(返回值列表):函数返回值的变量名以及类型,如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的。

如果有连续若干个参数的类型一致,那么只需在最后一个参数后添加该类型:

package main  
  
import "fmt"  
  
// 函数返回一个无名变量,返回值列表的括号省略  
func sum(x int, y int) int {  
    return x + y  
}  
  
// 无参数列表和返回值  
func printBookName() {  
    fmt.Println("go lang1.18")  
}  
  
// 参数的类型一致,只在最后一个参数后添加该类型  
func sub(x, y int) int {  
    return x - y  
}  
  
func main() {  
    fmt.Println("1 + 1 = ", sum(1, 1))  
    printBookName()  
    fmt.Println("2 - 1 =", sub(2, 1))  
}

程序返回:

command-line-arguments  
1 + 1 =  2  
go lang1.18  
2 - 1 = 1

不定长参数

和Python一样,Go lang也支持不定长参数,即参数有多少个并不确定的情况。

在参数类型前面加 ... 表示一个切片,用来接收调用者传入的参数。注意,如果该函数下有其他类型的参数,这些其他参数必须放在参数列表的前面,切片必须放在最后:

package main  
  
import "fmt"  
  
func show(args ...string) int {  
    sum := 0  
    for _, item := range args {  
        fmt.Println(item)  
        sum += 1  
    }  
    return sum  
}  
  
func main() {  
    fmt.Println(show("1", "2", "3"))  
}

和Python的*args用法差不多,但需要注意必须要声明函数的数据类型,程序返回:

1  
2  
3  
3

如果传多个参数的数据类型都不一样,可以指定类型为 ...interface{} ,然后再进行遍历:

package main  
  
import "fmt"  
  
func PrintType(args ...interface{}) {  
    for _, arg := range args {  
        switch arg.(type) {  
        case int:  
            fmt.Println(arg, "type is int.")  
        case string:  
            fmt.Println(arg, "type is string.")  
        case float64:  
            fmt.Println(arg, "type is float64.")  
        default:  
            fmt.Println(arg, "is an unknown type.")  
        }  
    }  
}  
  
func main() {  
    PrintType(1, 3.1415, "go lang 1.18")  
}

此外,还可以使用 ... 可以用来解序列,能将函数的可变参数(即切片)一个一个取出来,传递给另一个可变参数的函数,而不是传递可变参数变量本身:

package main  
  
import "fmt"  
  
func main() {  
    var s []string  
    s = append(s, []string{"1", "2", "3"}...)  
    fmt.Println(s)  
}

这里将字符串切片取出来后,传递给内置的append方法,程序返回:

[1 2 3]

函数的返回值

一个函数可以没有返回值,也可以有一个返回值,也可以有返回多个值:

package main  
  
import "fmt"  
  
func swap(x, y string) (string, string) {  
    return y, x  
}  
  
func SumAndProduct(A, B int) (add int, Multiplied int) {  
    add = A + B  
    Multiplied = A * B  
    return  
}  
  
func main() {  
    a, b := swap("Mahesh", "Kumar")  
    fmt.Println(a, b)  
  
    fmt.Println(SumAndProduct(1, 2))  
  
}

程序返回:

Kumar Mahesh  
3 2

\_ 是Go lang里的空白标识符。它可以代替任何类型的任何值。我们可以利用它来忽略某些别人会用到但我们不会用到的函数返回值:

package main  
  
import (  
    "fmt"  
)  
  
func rectProps(length, width float64) (float64, float64) {  
    var area = length * width  
    var perimeter = (length + width) * 2  
    return area, perimeter  
}  
func main() {  
    area, _ := rectProps(10.8, 5.6) // perimeter is discarded  
    fmt.Printf("Area %f ", area)  
}

程序返回:

Area 60.480000

匿名函数

有点类似Python中的lambda表达式,但实际上并不是作为语法糖而存在:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    f := func() {  
        fmt.Println("hello world")  
    }  
    f()                   //hello world  
    fmt.Printf("%T\n", f) //打印 func()  
}

程序返回:

hello world  
func()

一望而知,只是匿名而已,但通过变量可调用,另外也可以拥有参数:

package main  
  
import (  
   "fmt"  
)  
func main() {  
   f:=func(args string){  
      fmt.Println(args)  
   }  
   f("hello world")//hello world  
   //或  
   (func(args string){  
        fmt.Println(args)  
    })("hello world")//hello world  
    //或  
    func(args string) {  
        fmt.Println(args)  
    }("hello world") //hello world  
}

程序返回:

hello world  
hello world  
hello world

基本上,匿名函数和命名函数用法上并无二致。

闭包(closure)

很多语言都有闭包的概念,简单理解就是函数的嵌套:

package main  
  
import "fmt"  
  
func main() {  
    a := Fun()  
    b:=a("hello ")  
    c:=a("hello ")  
    fmt.Println(b)//worldhello   
    fmt.Println(c)//worldhello hello   
}  
func Fun() func(string) string {  
    a := "world"  
    return func(args string) string {  
        a += args  
        return  a  
    }  
}

程序返回:

worldhello   
worldhello hello

这里我们将方法作为参数传递到方法内部执行,这样内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。

延迟函数

延迟其实是延迟(defer)语句,延迟语句被用于执行一个函数调用,在这个函数之前,延迟语句返回:

package main  
  
import "fmt"  
  
func main() {  
    a := 1  
    b := 2  
    defer fmt.Println(b)  
    fmt.Println(a)  
}

程序返回:

1  
2

说白了就是一种倒装的形式,非延迟语句先执行,最后再执行延迟语句。

延迟也并不仅仅局限于函数内部语句,延迟一个方法调用也是可以的:

package main  
  
import (  
    "fmt"  
)  
  
type person struct {  
    firstName string  
    lastName  string  
}  
  
func (p person) fullName() {  
    fmt.Printf("%s %s", p.firstName, p.lastName)  
}  
  
func main() {  
    p := person{  
        firstName: "go lang",  
        lastName:  "python",  
    }  
    defer p.fullName()  
    fmt.Printf("Welcome ")  
}

程序返回:

Welcome go lang python

初始化函数

顾名思义,和Python中的魔法方法init一样,可以提前做一些初始化操作:

package main  
  
import "fmt"  
  
var a int = initVar()  
  
func init() {  
    fmt.Println("init2")  
}  
  
func init() {  
    fmt.Println("init")  
}  
  
func initVar() int {  
    fmt.Println("init var...")  
    return 100  
}  
  
func main() {  
    fmt.Println("main...")  
}

程序返回:

init var...  
init2  
init 

这里的初始化顺序是:变量初始化->init()->main()

和Python不同的是,每个包可以有多个初始化函数。

结语

归根结底,函数可以被认为是Go lang中的一种数据类型,可以作为另一个函数的参数,也可以作为另一个函数的返回值,使用起来相当灵活,但我们也不能矫枉过正,毫无节制地用函数封装逻辑,造成过度封装的现象。

相关文章
|
8天前
|
Go
go结构体的定义
go结构体的定义
11 1
|
15天前
|
算法 编译器 Go
Go语言中,常量和变量的定义和使用
Go语言中,常量和变量的定义和使用
|
19天前
|
Go
The “gopls“ command is not available. Run “go get -v golang.org/x/tools/gopls“ to install.【已解决】
The “gopls“ command is not available. Run “go get -v golang.org/x/tools/gopls“ to install.【已解决】
12 3
|
19天前
|
Go
【golang】Go 判断字符串是否包含指定字符
【golang】Go 判断字符串是否包含指定字符
13 1
|
8天前
|
Go
go常量显示定义、隐式定义、iota
go常量显示定义、隐式定义、iota
8 0
|
8天前
|
Go
go变量定义、变量交换、匿名变量
go变量定义、变量交换、匿名变量
8 0
|
14天前
|
Go
Go语言进阶篇——浅谈函数中的闭包
Go语言进阶篇——浅谈函数中的闭包
|
14天前
|
Go
go基础语法结束篇 ——函数与方法
go基础语法结束篇 ——函数与方法
|
2月前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
127 0
|
2月前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
75 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式