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

相关文章
|
15天前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
3月前
|
监控 Java 编译器
限流、控并发、减GC!一文搞懂Go项目资源优化的正确姿势
本章介绍Go语言项目在构建与部署阶段的性能调优和资源控制策略,涵盖编译优化、程序性能提升、并发与系统资源管理、容器化部署及自动化测试等内容,助力开发者打造高效稳定的生产级应用。
|
3月前
|
存储 安全 算法
Go语言泛型-泛型对代码结构的优化
Go语言自1.18版本引入泛型,极大提升了代码的通用性与可维护性。通过泛型,开发者可以减少重复代码、提高类型安全性,并增强程序的复用性和可读性。本文详细介绍了泛型在数据结构、算法及映射功能中的应用,展示了其在优化代码结构方面的优势。同时,Go编译器对泛型代码进行类型推导,确保运行时性能不受影响。合理使用泛型,有助于构建更加灵活高效的程序。
|
4月前
|
人工智能 Dart Go
Go语言中的make和new函数的区别及使用场景
本文详细解析了Go语言中`make`和`new`函数的使用方法及区别。`make`用于创建切片、映射和通道等引用类型,返回初始化后的值;`new`用于创建任意类型的零值对象,返回指向该对象的指针。文章通过多个示例说明两者的应用场景,并总结了面试中可能遇到的相关问题,如底层实现、使用场景及优缺点等,帮助读者更好地理解和区分这两个函数。
119 1
|
5月前
|
机器学习/深度学习 存储 监控
上网管理监控软件的 Go 语言流量特征识别算法实现与优化
本文探讨基于Go语言的流量特征识别算法,用于上网管理监控软件。核心内容涵盖AC自动机算法原理、实现及优化,通过路径压缩、哈希表存储和节点合并策略提升性能。实验表明,优化后算法内存占用降低30%,匹配速度提升20%。在1000Mbps流量下,CPU利用率低于10%,内存占用约50MB,检测准确率达99.8%。未来可进一步优化高速网络处理能力和融合机器学习技术。
149 10
|
5月前
|
Go 调度
GO语言函数的内部运行机制分析
以上就是Go语言中函数的内部运行机制的概述,展示了函数在Go语言编程中如何发挥作用,以及Go如何使用简洁高效的设计,使得代码更简单,更有逻辑性,更易于理解和维护。尽管这些内容深入了一些底层的概念,但我希望通过这种方式,将这些理论知识更生动、更形象地带给你,让你在理解的同时找到编程的乐趣。
77 5
|
5月前
|
Go Python
函数的定义与调用 -《Go语言实战指南》
本文介绍了 Go 语言中函数的核心特性与用法,包括基本定义格式、调用方式、多返回值、返回值命名、参数类型简写、可变参数、高阶函数及匿名函数等内容。通过示例代码详细展示了如何定义和使用不同类型的函数,使读者能够全面了解 Go 函数的灵活性与强大功能。
|
11月前
|
存储 负载均衡 监控
如何利用Go语言的高效性、并发支持、简洁性和跨平台性等优势,通过合理设计架构、实现负载均衡、构建容错机制、建立监控体系、优化数据存储及实施服务治理等步骤,打造稳定可靠的服务架构。
在数字化时代,构建高可靠性服务架构至关重要。本文探讨了如何利用Go语言的高效性、并发支持、简洁性和跨平台性等优势,通过合理设计架构、实现负载均衡、构建容错机制、建立监控体系、优化数据存储及实施服务治理等步骤,打造稳定可靠的服务架构。
222 1
|
11月前
|
JSON 安全 网络协议
go语言使用内置函数和标准库
【10月更文挑战第18天】
142 3
|
10月前
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数

推荐镜像

更多