go函数使用(一)

简介: go函数使用

介绍

每一个程序都包含很多的函数:函数是基本的代码块。

Go是编译型语言,所以函数编写的顺序是无关紧要的;鉴于可读性的需求,最好把 main() 函数写在文件的前面,其他函数按照一定逻辑顺序进行编写(例如函数被调用的顺序)。

Go 里面拥三种类型的函数:

  • 普通的带有名字的函数
  • 匿名函数或者lambda函数
  • 方法
    所有类型的函数都可以有参数与返回值。函数参数、返回值以及它们的类型被统称为函数签名。
    注意
    go语言方法后面要紧跟大括号
    这样是不正确的 Go 代码:
func g()
{
}

它必须是这样的:

func g() {
}

函数被调用的基本格式如下:

pack1.Function(arg1, arg2, …, argn)

Function 是 pack1 包里面的一个函数,括号里的是被调用函数的实参(argument):这些值被传递给被调用函数的形参(parameter)。

一个简单的函数调用其他函数的例子:

package main
func main() {
println("In main before calling greeting")
greeting()
println("In main after calling greeting")
}
func greeting() {
println("In greeting: Hi!!!!!")
}

代码输出:

In main before calling greeting

In greeting: Hi!!!

In main after calling greeting

注意

函数可以将其他函数调用作为它的参数,只要这个被调用函数的返回值个数、返回值类型和返回值的顺序与调用函数所需求的实参是一致的,例如:

假设 f1 需要 3 个参数 f1(a, b, c int) ,同时 f2 返回 3 个参数 f2(a, b int) (int, int, int) ,就可以这样调用 f1: f1(f2(a, b)) 。

注意在 Go 里面函数重载是不被允许的。这将导致一个编译错误:funcName redeclared in this book, previous declaration at lineno

Go 语言不支持这项特性的主要原因是函数重载需要进行多余的类型匹配影响性能;没有重载意味着只是一个简单的函数调度。所以你需要给不同的函数使用不同的名字,我们通常会根据函数的特征对函数进行命名。如果需要申明一个在外部定义的函数,你只需要给出函数名与函数签名,不需要给出函数体:

func flushICache(begin, end uintptr) // implemented externally

函数也可以以申明的方式被使用,作为一个函数类型,就像:type binOp func(int, int) int在这里,不需要函数体 {} 。

函数参数与返回值

  • 按值传递(call by value) 按引用传递(call by reference)
  • 命名的返回值(named return variables)
  • 空白符(blank identifier)
  • 改变外部变量(outside variable)

函数能够接收参数供自己使用,也可以返回零个或多个值(我们通常把返回多个值称为返回一组值)。多值返回是 Go 的一大特性,为我们判断一个函数是否正常执行提供了方便。

我们通过 return 关键字返回一组值。事实上,任何一个有返回值(单个或多个)的函数都必须以return 或 panic 结尾。

在函数块里面, return 之后的语句都不会执行。如果一个函数需要返回值,那么这个函数里面的每一个代码分支(code-path)都要有 return 语句。

按值传递 按引用传递

Go 默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不会影响到原来的变量,比如 Function(arg1) 。

如果你希望函数可以直接修改参数的值,而不是对参数的副本进行操作,你需要将参数的地址(变量名前面添加&符号,比如 &variable)传递给函数,这就是按引用传递,比如 Function(&arg1) ,此时传递给函数的是一个指针。如果传递给函数的是一个指针,指针的值(一个地址)会被复制,但指针的值所指向的地址上的值不会被复制;我们可以通过这个指针的值来修改这个值所指向的地址上的值。

几乎在任何情况下,传递指针(一个32位或者64位的值)的消耗都比传递副本来得少。

在函数调用时,像切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递(即使没有显示的指出指针)。

package main
import "fmt"
func main() {
fmt.Printf("Multiply 2 * 5 * 6 = %d\n", MultiPly3Nums(2, 5, 6))
// var i1 int = MultiPly3Nums(2, 5, 6)
// fmt.Printf("MultiPly 2 * 5 * 6 = %d\n", i1)
}
func MultiPly3Nums(a int, b int, c int) int {
// var product int = a * b * c
// return product
return a * b * c
}

输出显示:

Multiply 2 * 5 * 6 = 60

如果一个函数需要返回四到五个值,我们可以传递一个切片给函数(如果返回值具有相同类型)或者是传递一个结构体(如果返回值具有不同的类型)。因为传递一个指针允许直接修改变量的值,消耗也更少。

命名的返回值(named return variables)

函数带有一个 int 参数,返回两个 int 值;其中一个函数的返回值在函数调用时就已经被赋予了一个初始零值。getX2AndX3 与 getX2AndX3_2 两个函数演示了如何使用非命名返回值与命名返回值的特性。当需要返回多个非命名返回值时,需要使用 () 把它们括起来,比如 (int, int) 。命名返回值作为结果形参(result parameters)被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的return语句。需要注意的是,即使只有一个命名返回值,也需要使用 () 括起来。

package main
import "fmt"
var num int = 10
var numx2, numx3 int
func main() {
numx2, numx3 = getX2AndX3(num)
PrintValues()
numx2, numx3 = getX2AndX3_2(num)
PrintValues()
}
func PrintValues() {
fmt.Printf("num = %d, 2x num = %d, 3x num = %d\n", num, numx2, numx3)
}
func getX2AndX3(input int) (int, int) {
return 2 * input, 3 * input
}
func getX2AndX3_2(input int) (x2 int, x3 int) {
x2 = 2 * input
x3 = 3 * input
// return x2, x3
return
}

输出结果:

num = 10, 2x num = 20, 3x num = 30

num = 10, 2x num = 20, 3x num = 30

警告

return 或 return var 都是可以的。

不过 return var = expression (表达式) 会引发一个编译错误:

syntax error: unexpected =, expecting semicolon or newline or } 。

空白符(blank identifier)

空白符用来匹配一些不需要的值,然后丢弃掉,下面的 blank_identifier.go 就是很好的例子。ThreeValues 是拥有三个返回值的不需要任何参数的函数,在下面的例子中,我们将第一个与第三个返回值赋给了 i1 与 f1 。第二个返回值赋给了空白符 _ ,然后自动丢弃掉。

package main
import "fmt"
func main() {
var i1 int
var f1 float32
i1, _, f1 = ThreeValues()
fmt.Printf("The int: %d, the float: %f \n", i1, f1)
}
func ThreeValues() (int, int, float32) {
return 5, 6, 7.5
}

输出结果:

The int: 5, the float: 7.500000

改变外部变量

传递指针给函数不但可以节省内存,而且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return 返回。如下的例子, reply 是一个指向 int 变量的指针,通过这个指针,我们在函数内修改了这个 int 变量的数值。

package main
import (
"fmt"
)
// this function changes reply:
func Multiply(a, b int, reply *int) {
*reply = a * b
}
func main() {
n := 0
reply := &n
Multiply(10, 5, reply)
fmt.Println("Multiply:", *reply) // Multiply: 50
}

然而,如果不小心使用的话,传递一个指针很容易引发一些不确定的事,所以,我们要十分小心那些可以改变外部变量的函数,在必要时,需要添加注释以便其他人能够更加清楚的知道函数里面到底发生了什么。

传递变长参数

如果函数的最后一个参数是采用 …type 的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变参函数。

func myFunc(a, b, arg ...int) {}

示例函数和调用:

func Greeting(prefix string, who ...string)
Greeting("hello:", "Joe", "Anna", "Eileen")

在 Greeting 函数中,变量 who 的值为 []string{“Joe”, “Anna”, “Eileen”} 。

如果参数被存储在一个数组 arr 中,则可以通过 arr… 的形式来传递参数调用变参函数。

package main
import "fmt"
func main() {
x := Min(1, 3, 2, 0)
fmt.Printf("The minimum is: %d\n", x)
arr := []int{7,9,3,5,1}
x = Min(arr...)
fmt.Printf("The minimum in the array arr is: %d", x)
}
func Min(a ...int) int {
if len(a)==0 {
return 0
}
min := a[0]
for _, v := range a {
if v < min {
min = v
}
}
return min
}


go函数使用(二)https://developer.aliyun.com/article/1391409

相关文章
|
5月前
|
JSON JavaScript Go
Go 语言学习指南:变量、循环、函数、数据类型、Web 框架等全面解析
掌握 Go 语言的常见概念,如变量、循环、条件语句、函数、数据类型等等。深入了解 Go 基础知识的好起点是查阅 Go 官方文档
485 2
|
5月前
|
Go
Go 语言输出文本函数详解
Go语言拥有三个用于输出文本的函数: Print() Println() Printf() Print() 函数以其默认格式打印其参数。
36 0
|
5月前
|
编译器 Go
Go 语言基础:包、函数、语句和注释解析
一个 Go 文件包含以下几个部分: 包声明 导入包 函数 语句和表达式 看下面的代码,更好地理解它:
46 0
|
5月前
|
存储 Go
Go 语言函数、参数和返回值详解
函数是一组语句,可以在程序中重复使用。函数不会在页面加载时自动执行。函数将通过调用函数来执行。
76 0
|
3天前
|
存储 Go 开发者
【Go语言专栏】函数在Go语言中的使用与实现
【4月更文挑战第30天】本文介绍了Go语言中函数的使用和实现,包括函数定义、参数传递、返回值、匿名函数、变长参数、函数类型、闭包和错误处理。通过示例展示了如何定义和调用函数,以及如何利用闭包和递归解决问题。此外,还提到了Go函数作为一等公民的特性,允许存储和传递。进一步学习可参考官方文档和相关书籍。
|
8天前
|
Go
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
【4月更文挑战第21天】Go语言函数是代码组织的基本单元,用于封装可重用逻辑。本文介绍了函数定义(包括基本形式、命名、参数列表和多返回值)、调用以及匿名函数与闭包。在函数定义时,注意参数命名和注释,避免参数顺序混淆。在调用时,要检查并处理多返回值中的错误。理解闭包原理,小心处理外部变量引用,以提升代码质量和可维护性。通过实践和示例,能更好地掌握Go语言函数。
22 1
Golang深入浅出之-Go语言函数基础:定义、调用与多返回值
|
10天前
|
程序员 Go API
【Go语言快速上手(二)】 分支与循环&函数讲解
【Go语言快速上手(二)】 分支与循环&函数讲解
|
10天前
|
存储 Go 开发者
Golang深入浅出之-Go语言字符串操作:常见函数与面试示例
【4月更文挑战第20天】Go语言字符串是不可变的字节序列,采用UTF-8编码。本文介绍了字符串基础,如拼接(`+`或`fmt.Sprintf()`)、长度与索引、切片、查找与替换(`strings`包)以及转换与修剪。常见问题包括字符串不可变性、UTF-8编码处理、切片与容量以及查找与替换的边界条件。通过理解和实践这些函数及注意事项,能提升Go语言编程能力。
22 0
|
14天前
|
自然语言处理 数据挖掘 程序员
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(下)
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(上)
26 1
|
14天前
|
数据采集 搜索推荐 Go
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)(上)
《Go 简易速速上手小册》第2章:控制结构与函数(2024 最新版)
25 1