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

相关文章
|
10月前
|
Java 编译器 Go
【Golang】(1)Go的运行流程步骤与包的概念
初次上手Go语言!先来了解它的运行流程吧! 在Go中对包的概念又有怎样不同的见解呢?
456 4
|
10月前
|
Java 编译器 Go
【Golang】(5)Go基础的进阶知识!带你认识迭代器与类型以及声明并使用接口与泛型!
好烦好烦好烦!你是否还在为弄不懂Go中的泛型和接口而烦恼?是否还在苦恼思考迭代器的运行方式和意义?本篇文章将带你了解Go的接口与泛型,还有迭代器的使用,附送类型断言的解释
426 3
|
10月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
454 2
|
Go 开发者
go-carbon v2.6.0 重大版本更新,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持
383 3
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
691 1
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
681 0

热门文章

最新文章