化整为零优化重用,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中的一种数据类型,可以作为另一个函数的参数,也可以作为另一个函数的返回值,使用起来相当灵活,但我们也不能矫枉过正,毫无节制地用函数封装逻辑,造成过度封装的现象。

相关文章
|
6天前
|
Go 数据处理
Go杂记1-切片Slice作为函数参数那点事儿
Go杂记1-切片Slice作为函数参数那点事儿
7 0
|
6天前
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
142 1
|
6天前
|
缓存 测试技术 持续交付
Golang深入浅出之-Go语言中的持续集成与持续部署(CI/CD)
【5月更文挑战第5天】本文介绍了Go语言项目中的CI/CD实践,包括持续集成与持续部署的基础知识,常见问题及解决策略。测试覆盖不足、版本不一致和构建时间过长是主要问题,可通过全面测试、统一依赖管理和利用缓存优化。文中还提供了使用GitHub Actions进行自动化测试和部署的示例,强调了持续优化CI/CD流程以适应项目需求的重要性。
57 1
|
6天前
|
Kubernetes Cloud Native Go
Golang深入浅出之-Go语言中的云原生开发:Kubernetes与Docker
【5月更文挑战第5天】本文探讨了Go语言在云原生开发中的应用,特别是在Kubernetes和Docker中的使用。Docker利用Go语言的性能和跨平台能力编写Dockerfile和构建镜像。Kubernetes,主要由Go语言编写,提供了方便的客户端库与集群交互。文章列举了Dockerfile编写、Kubernetes资源定义和服务发现的常见问题及解决方案,并给出了Go语言构建Docker镜像和与Kubernetes交互的代码示例。通过掌握这些技巧,开发者能更高效地进行云原生应用开发。
58 1
|
6天前
|
负载均衡 监控 Go
Golang深入浅出之-Go语言中的服务网格(Service Mesh)原理与应用
【5月更文挑战第5天】服务网格是处理服务间通信的基础设施层,常由数据平面(代理,如Envoy)和控制平面(管理配置)组成。本文讨论了服务发现、负载均衡和追踪等常见问题及其解决方案,并展示了使用Go语言实现Envoy sidecar配置的例子,强调Go语言在构建服务网格中的优势。服务网格能提升微服务的管理和可观测性,正确应对问题能构建更健壮的分布式系统。
30 1
|
Go Windows 编译器
window 下 go lang 环境变量一键批处理设置
目的,就是为了我这种贼懒得人用的 作者:风来了.呆狐狸 使用的是GO lang ZIP压缩包安装 ,可以自动设置环境变量 GO lang下载地址:http://www.golangtc.com/download 使用方法 保存为 go.bat 放到go 目录内,执行go.bat即可,其中GOARCH 要根据自己系统位数设置,这边是64位系统 原理:setx 设置用户环境变量
1452 0
|
23小时前
|
存储 安全 编译器
go语言中进行不安全的类型操作
【5月更文挑战第10天】Go语言中的`unsafe`包提供了一种不安全但强大的方式来处理类型转换和底层内存操作。包含两个文档用途的类型和八个函数,本文也比较了不同变量和结构体的大小与对齐系数,强调了字段顺序对内存分配的影响。
32 8
go语言中进行不安全的类型操作
|
1天前
|
Go
配置go语言下载包 - 蓝易云
这个命令会将包下载到你的GOPATH目录下,并自动安装它。
18 1
|
2天前
|
安全 Go 调度
Go语言中的并发编程
Go语言自带了强大的并发编程能力,它的协程机制可以让程序轻松地实现高并发。本文将从并发编程的基础概念出发,介绍Go语言中的协程机制、通道和锁等相关知识点,帮助读者更好地理解并发编程在Go语言中的实践应用。
|
3天前
|
Ubuntu Unix Linux
【GO基础】1. Go语言环境搭建
【GO基础】1. Go语言环境搭建