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

函数声明

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

  1. func function_name(parameter_list) (result_list) {
  2. //函数逻辑
  3. }

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

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

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

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

  1. package main
  2. import "fmt"
  3. // 函数返回一个无名变量,返回值列表的括号省略
  4. func sum(x int, y int) int {
  5. return x + y
  6. }
  7. // 无参数列表和返回值
  8. func printBookName() {
  9. fmt.Println("go lang1.18")
  10. }
  11. // 参数的类型一致,只在最后一个参数后添加该类型
  12. func sub(x, y int) int {
  13. return x - y
  14. }
  15. func main() {
  16. fmt.Println("1 + 1 = ", sum(1, 1))
  17. printBookName()
  18. fmt.Println("2 - 1 =", sub(2, 1))
  19. }

程序返回:

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

不定长参数

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

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

  1. package main
  2. import "fmt"
  3. func show(args ...string) int {
  4. sum := 0
  5. for _, item := range args {
  6. fmt.Println(item)
  7. sum += 1
  8. }
  9. return sum
  10. }
  11. func main() {
  12. fmt.Println(show("1", "2", "3"))
  13. }

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

  1. 1
  2. 2
  3. 3
  4. 3

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

  1. package main
  2. import "fmt"
  3. func PrintType(args ...interface{}) {
  4. for _, arg := range args {
  5. switch arg.(type) {
  6. case int:
  7. fmt.Println(arg, "type is int.")
  8. case string:
  9. fmt.Println(arg, "type is string.")
  10. case float64:
  11. fmt.Println(arg, "type is float64.")
  12. default:
  13. fmt.Println(arg, "is an unknown type.")
  14. }
  15. }
  16. }
  17. func main() {
  18. PrintType(1, 3.1415, "go lang 1.18")
  19. }

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

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

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

  1. [1 2 3]

函数的返回值

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

  1. package main
  2. import "fmt"
  3. func swap(x, y string) (string, string) {
  4. return y, x
  5. }
  6. func SumAndProduct(A, B int) (add int, Multiplied int) {
  7. add = A + B
  8. Multiplied = A * B
  9. return
  10. }
  11. func main() {
  12. a, b := swap("Mahesh", "Kumar")
  13. fmt.Println(a, b)
  14. fmt.Println(SumAndProduct(1, 2))
  15. }

程序返回:

  1. Kumar Mahesh
  2. 3 2

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func rectProps(length, width float64) (float64, float64) {
  6. var area = length * width
  7. var perimeter = (length + width) * 2
  8. return area, perimeter
  9. }
  10. func main() {
  11. area, _ := rectProps(10.8, 5.6) // perimeter is discarded
  12. fmt.Printf("Area %f ", area)
  13. }

程序返回:

  1. Area 60.480000

匿名函数

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. f := func() {
  7. fmt.Println("hello world")
  8. }
  9. f() //hello world
  10. fmt.Printf("%T\n", f) //打印 func()
  11. }

程序返回:

  1. hello world
  2. func()

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. f:=func(args string){
  7. fmt.Println(args)
  8. }
  9. f("hello world")//hello world
  10. //或
  11. (func(args string){
  12. fmt.Println(args)
  13. })("hello world")//hello world
  14. //或
  15. func(args string) {
  16. fmt.Println(args)
  17. }("hello world") //hello world
  18. }

程序返回:

  1. hello world
  2. hello world
  3. hello world

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

闭包(closure)

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

  1. package main
  2. import "fmt"
  3. func main() {
  4. a := Fun()
  5. b:=a("hello ")
  6. c:=a("hello ")
  7. fmt.Println(b)//worldhello
  8. fmt.Println(c)//worldhello hello
  9. }
  10. func Fun() func(string) string {
  11. a := "world"
  12. return func(args string) string {
  13. a += args
  14. return a
  15. }
  16. }

程序返回:

  1. worldhello
  2. worldhello hello

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

延迟函数

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

  1. package main
  2. import "fmt"
  3. func main() {
  4. a := 1
  5. b := 2
  6. defer fmt.Println(b)
  7. fmt.Println(a)
  8. }

程序返回:

  1. 1
  2. 2

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

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type person struct {
  6. firstName string
  7. lastName string
  8. }
  9. func (p person) fullName() {
  10. fmt.Printf("%s %s", p.firstName, p.lastName)
  11. }
  12. func main() {
  13. p := person{
  14. firstName: "go lang",
  15. lastName: "python",
  16. }
  17. defer p.fullName()
  18. fmt.Printf("Welcome ")
  19. }

程序返回:

  1. Welcome go lang python

初始化函数

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

  1. package main
  2. import "fmt"
  3. var a int = initVar()
  4. func init() {
  5. fmt.Println("init2")
  6. }
  7. func init() {
  8. fmt.Println("init")
  9. }
  10. func initVar() int {
  11. fmt.Println("init var...")
  12. return 100
  13. }
  14. func main() {
  15. fmt.Println("main...")
  16. }

程序返回:

  1. init var...
  2. init2
  3. init

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

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

结语

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

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

  1. 仙人指路,引而不发,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中New和Make函数的使用背景和区别EP16

    Golang只有二十五个系统保留关键字,二十几个系统内置函数,加起来只有五十个左右需要记住的关键字,纵观编程宇宙,无人能出其右.其中还有一些保留关键字属于"锦上添花",什么叫锦上添 ...

  2. 延宕执行,妙用无穷,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中defer关键字延迟调用机制使用EP17

    先行定义,延后执行.不得不佩服Go lang设计者天才的设计,事实上,defer关键字就相当于Python中的try{ ...}except{ ...}finally{...}结构设计中的finall ...

  3. 清源正本,鉴往知来,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中引用类型是否进行引用传递EP18

    开篇明义,Go lang中从来就不存在所谓的"引用传递",从来就只有一种变量传递方式,那就是值传递.因为引用传递的前提是存在"引用变量",但是Go lang中从 ...

  4. 你有对象类,我有结构体,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang结构体(struct)的使用EP06

    再续前文,在面向对象层面,Python做到了超神:万物皆为对象,而Ruby,则干脆就是神:飞花摘叶皆可对象.二者都提供对象类操作以及继承的方式为面向对象张目,但Go lang显然有一些特立独行,因为它 ...

  5. 百亿数据百亿花, 库若恒河沙复沙,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang数据库操作实践EP12

    Golang可以通过Gorm包来操作数据库,所谓ORM,即Object Relational Mapping(数据关系映射),说白了就是通过模式化的语法来操作数据库的行对象或者表对象,对比相对灵活繁复 ...

  6. 层次分明井然有条,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang包管理机制(package)EP10

    Go lang使用包(package)这种概念元素来统筹代码,所有代码功能上的可调用性都定义在包这个级别,如果我们需要调用依赖,那就"导包"就行了,无论是内部的还是外部的,使用im ...

  7. 兔起鹘落全端涵盖,Go lang1.18入门精炼教程,由白丁入鸿儒,全平台(Sublime 4)Go lang开发环境搭建EP00

    Go lang,为并发而生的静态语言,源于C语言又不拘泥于性能,高效却不流于古板,Python灵活,略输性能,Java严谨,稍逊风骚.君不见各大厂牌均纷纷使用Go lang对自己的高并发业务进行重构, ...

  8. 因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15

    事实上,泛型才是Go lang1.18最具特色的所在,但为什么我们一定要拖到后面才去探讨泛型?类比的话,我们可以想象一下给小学一年级的学生讲王勃的千古名篇<滕王阁序>,小学生有多大的概率可 ...

  9. 巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09

    流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序.众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang程序的流程控制结构一共有三种: ...

随机推荐

  1. freeswitch使用mod_shout模块播放mp3

    概述 freeswitch 在对VOIP语音通话中,可以通过playback命令播放IVR语音文件. 默认情况下,freeswitch支持wav文件,也可以直接播放VOIP中常见编解码的G711文件. ...

  2. Grafana+Prometheus 搭建 JuiceFS 可视化监控系统

    作为承载海量数据存储的分布式文件系统,用户通常需要直观地了解整个系统的容量.文件数量.CPU 负载.磁盘 IO.缓存等指标的变化. JuiceFS 没有重复造轮子,而是通过 Prometheus 兼容 ...

  3. linux 查询文件命令

    jps; 当前服务器中所有的java进程: jps |grep XXX; 查询当前服务器某个进程: locate xxx;查询某个文件的位置:

  4. 数组——JavaSE基础

    数组 数组初始化 public class ArrayDemo02 { public static void main(String[] args) { // 静态初始化 int[] a = {1, ...

  5. SpringCloud 配置管理:Nacos

    目录 统一配置管理 配置热更新 配置共享 多环境配置共享 多服务配置共享 统一配置管理 将配置交给 Nacos 管理的步骤: 在 Nacos 中添加配置文件. 在微服务中引入 nacos 的 conf ...

  6. Java-SpringBoot-使用多态给项目解耦

    Java-SpringBoot-使用多态给项目解耦 提及 今天在打算维护一下智慧社区这个项目的时候,想到项目是使用Satoken这个开箱即用的授权和认证的组件,因为在项目开启的时候对SpringSec ...

  7. C语言:如何给全局变量起一个别名?

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  8. Windows下MySQL的安装和删除

    Windows下MySQL的安装和删除 安装Mysql 1 下载mysql 地址 2 安装教程 2.1配置环境变量 变量名:MYSQL_HOME 变量值:D:\software\programming ...

  9. WPF开发随笔收录-DrawingVisual绘制高性能曲线图

    一.前言 项目中涉及到了心率监测,而且数据量达到了百万级别,通过WPF实现大数据曲线图时,尝试过最基础的Canvas来实现,但是性能堪忧,而且全部画出来也不实际.同时也尝试过找第三方的开源库,但是因为 ...

  10. 下载安装myslq-----win

    在百度上搜索MySQL官网,进入下载页面-->选择社区版(Community)-->选择MySQL Community Server后,点击DOWNLOAD按钮-->Generall ...