Golang教程:函数、变参函数
函数是完成一个特定任务的代码块。一个函数接受输入,对输入进行一些运算并产生输出。
函数声明
在 Go 中声明一个函数的语法为:
func functionname(parametername type) returntype {
//function body
}
函数声明以关键字 func 开头,后面是函数名字,接着是在 ( 和 ) 之间指定的参数列表,然后是函数的返回类型。指定参数的语法为参数名称后面跟着参数类型。可以指定任意数量的参数,形式为: (parameter1 type, parameter2 type)。最后是由 { 和 } 以及它们之间的代码块组成的函数体。
在一个函数中,参数和返回值是可选的。因此下面的语法也是合法的函数声明:
func functionname() {
}
函数的例子
让我们写一个函数,它以单个产品的价格和产品数量作为输入参数,并以总价格(单个产品的价格与产品数量的乘积)作为返回值。
func calculateBill(price int, no int) int {
var totalPrice = price * no
return totalPrice
}
上面的函数接受两个 int 类型的输入参数:price 和 no,并返回 totalPrice(price 与 no 的乘积) 。返回值的类型也是 int。
如果连续的参数具有相同的类型,我们可以避免每次都写出它们的类型,只需要在结束的时候写一次就可以了,比如:price int, no int 可以写成:price, no int。 于是上面的函数可以写成:
func calculateBill(price, no int) int {
var totalPrice = price * no
return totalPrice
}
我们已经定义好了我们函数,现在让我们在代码中调用它。调用函数的语法为:functionname(parameters)。上面定义的函数 calculateBill 可以通过下面的代码调用:
calculateBill(, )
下面是完整的程序,它调用 calculateBill 并计算总价格。
package main import (
"fmt"
) func calculateBill(price, no int) int {
var totalPrice = price * no
return totalPrice
}
func main() {
price, no := ,
totalPrice := calculateBill(price, no)
fmt.Println("Total price is ", totalPrice)
}
多个返回值
一个函数可以返回多个值。让我们写一个函数 rectProps,它接受一个矩形的长和宽,并返回该矩形的面积和周长。矩形的面积为长与宽的积。周长为长与宽的和的 2 倍。
package main import (
"fmt"
) func rectProps(length, width float64)(float64, float64) {
var area = length * width
var perimeter = (length + width) *
return area, perimeter
} func main() {
area, perimeter := rectProps(10.8, 5.6)
fmt.Printf("Area %f Perimeter %f", area, perimeter)
}
如果一个函数有多个返回值,那么这些返回值应该用小括号()括起来,比如:func rectProps(length, width float64)(float64, float64) 接受两个类型为 float64 的参数(length 和 width),并且同样返回两个类型为 float64 的返回值。上面程序的输出为:Area 60.480000 Perimeter 32.800000
具名返回值
可以给一个函数的返回值指定名字。如果指定了一个返回值的名字,则可以视为在该函数的第一行中定义了该名字的变量。
上面的 rectProps 函数可以用具名返回值的形式重写如下:
func rectProps(length, width float64)(area, perimeter float64) {
area = length * width
perimeter = (length + width) *
return //no explicit return value
}
在上面的函数中,area 和 perimeter 是具名返回值。注意 return 语句没有指定任何返回值。因为在函数声明时已经指定area 和 perimeter 是返回值,在遇到 return 语句时它们会自动从函数中返回。
空指示符
在 Go 中,下划线(_)表示空指示符(blank identifier)。它可以用于代替任何类型的任何值。让我们看看如何使用空指示符。
我们知道上面定义的函数 rectProps 返回矩形的面积(area)和周长(perimeter)。如果我们只需要获取 area 而想要忽略 perimeter该怎么办呢?这时候就可以使用空指示符。
下面的程序仅接收 rectProps 返回的 area:
package main import (
"fmt"
) func rectProps(length, width float64) (float64, float64) {
var area = length * width
var perimeter = (length + width) *
return area, perimeter
}
func main() {
area, _ := rectProps(10.8, 5.6) // perimeter is discarded
fmt.Printf("Area %f ", area)
}
在 area, _ := rectProps(10.8, 5.6) 这一行,我们仅仅获取了 area,而使用空指示符 _ 来忽略第二个返回值(perimeter)。
什么是变参函数?
变参函数是指可以接受可变数量的参数的函数。
语法
如果一个函数的最后一个参数由 ...T 表示,则表示该函数可以接受任意数量的类型为 T 的参数。
请注意只有函数的最后一个参数才能指定为可变参数。
例子
你有没有想过为什么 append 函数可以将任意数量的值追加到切片末尾?这是因为它是一个变参函数。append 的原型为 func append(slice []Type, elems ...Type) []Type,其中 elems 是一个可变参数。
让我们来创建一个自己的变参函数。我们将编写一个程序来判断某个特定整数是否包含在某个整数列表中。
package main import (
"fmt"
) func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
find(, , , )
find(, , , , , )
find(, , , )
find()
}
上面的程序中,func find(num int, nums ...int) 可以接受任意数量的参数。...int 在内部表示为切片。在这里 nums的类型为 []int。
第 10 行利用 range for 遍历 nums 切片,如果找到 num 则打印 num 所在位置,否则打印没有找到。
上面的程序输出如下:
type of nums is []int
found at index in [ ] type of nums is []int
found at index in [ ] type of nums is []int
not found in [ ] type of nums is []int
not found in []
在第 25 行,find 只有一个参数。我们没有传递任何参数给 nums ...int。这是合法的,(译者注:如果没有给可变参数传递任何值,则可变参数为 nil 切片),在这里 nums 是一个 nil 切片,长度和容量都是0。
传递切片给可变参数
我们已经提到 ...T 在内部表示为类型是 []T 切片。如果真是这样,可以传递一个切片给可变参数吗?让我们从下面的例子中寻找答案:
package main import (
"fmt"
) func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
nums := []int{, , }
find(, nums)
}
在第 23 行,我们没有将若干数量的参数传递给 find 的最后一个参数, 而是传递了一个切片。这是非法的,我们不能传递一个切片给可变参数。上面的程序将报错:main.go:23: cannot use nums (type []int) as type int in argument to find。
这里有一个语法糖可以用来将切片传递给变参函数。可以在切片后面加 ...,这样会将切片展开为其中的各个元素并将它们传递给变参函数。这样该程序将正常工作。
上面的程序如果将第23行的 find(89, nums) 改为 find(89, nums...),程序将通过编译,并输出如下:
type of nums is []int
found at index in [ ]
Golang教程:函数、变参函数的更多相关文章
- Golang简单入门教程——函数进阶篇
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第八篇,我们来聊聊golang当中的函数. 我们在之前的时候已经介绍过了函数的基本用法,知道了怎么样设计或者是定义一 ...
- golang的函数
在golang中, 函数是第一类值(first-class object), 即函数可以赋值与被赋值. 换言之, 函数也可以作为ReceiverType, 定义自己的method. 实例: http. ...
- golang(06)函数介绍
原文链接 http://www.limerence2017.com/2019/09/11/golang11/#more 函数简介 函数是编程语言中不可缺少的部分,在golang这门语言中函数是一等公民 ...
- golang笔记——函数与方法
如果你遇到没有函数体的函数声明,表示该函数不是以Go实现的. package math func Sin(x float64) float //implemented in assembly lang ...
- Golang教程:数组和切片
数组 数组是类型相同的元素的集合.例如,整数 5, 8, 9, 79, 76 的集合就构成了一个数组.Go不允许在数组中混合使用不同类型的元素(比如整数和字符串). 声明 var variable_n ...
- Golang tips ----- 函数
1.在函数调用时,Golang没有默认参数值 2.一个函数声明如果没有函数体,表面该函数不是由Golang实现的,这样的声明定义了函数标识符 3.拥有函数名的函数只能在包级语法块中被声明 4.函数值( ...
- golang 原子操作函数
golang中的原子操作在sync/atomic package中. 下文以比较和交换操作函数为例,介绍其使用. CompareAndSwapInt32 比较和交换操作是原子性的. // Compar ...
- Golang之函数练习
小例题: package main import "fmt" /* 函数练习, 可变参数使用 写一个函数add 支持1个或多个int相加,并返回相加结果 写一个函数concat,支 ...
- [golang note] 函数定义
普通函数定义 √ golang函数基本组成:关键字func.函数名.参数列表.返回值.函数体和返回语句. • 语法如下 func 函数名(参数列表) (返回值列表) { // 函数体 } • 示例如下 ...
随机推荐
- Cntlm
SourceForge页面 作用是转发请求到代理 可以同时加上域验证信息(为各种NTLM认证?) gradle.cmd.Terminal等工具或软件可能无法或者说没有使用系统/浏览器设置的代理,因为可 ...
- Python 的web自动化测试
安装selenium 上面python已安装完毕,接下来安装selenium. 安装selenium之前需安装些必要工具 1. 安装setuptools 下载地址:https://pypi.pytho ...
- linux 修改主机名 【root@主机名 ~】
centos 7修改方式: hostnamectl set-hostname hostuser reboot 或者直接vi /etc/hostname 添加内容: hostuser 检查修改效果 ...
- [BZOJ]4650 优秀的拆分(Noi2016)(哈希+二分)
传送门 题解 听说大佬们这题都是用SA秒掉的 然而SA的时间复杂度的确很优秀,缺点就是看不太懂…… 然后发现一位大佬用哈希华丽的过了此题,而且讲的特别清楚->这里 我们只要考虑以每一个点结尾 ...
- centos6.5 命令行配置无线上网
1.驱动下载地址: RTL8188无线网卡驱动下载 链接:https://pan.baidu.com/s/1ms-EbQCDxa76jPhYUPmr9Q 密码:r2vu 2.安装步骤: [root@c ...
- 常用博客 API地址
新浪博客 http://upload.move.blog.sina.com.cn/blog_rebuild/blog/xmlrpc.php 网易博客 http://os.blog.163.com/ap ...
- 斐讯K2P配置文件破解笔记
手上有一个斐讯K2P路由器,刷机前我想把原机带的固件备份出来.搜到恩山A大开启telnet.固件备份的教程,里面提到了配置文件破解的方法,心血来潮试了一下,发现算出的密码不能解密,一直报"b ...
- HTML-基础及一般标签
HTML 内容 Hyper Text Markup Language 超文本标记语言(包含文本.表格.图片.声音.视频等,同时也是文档) HTML 元素指的是从开始标签(start t ...
- (USB HID) VC++ 使用 SetupAPI 操作 USB HID Device
在VC裡頭使用 Api必須include 跟加入 lib,加入之後就可以在VC裡頭任意使用api了 暫時先貼上程式碼...等待有空時候在更新說明 extern "C" { #inc ...
- fetch网络请求 get 和 post
//在React Native中,使用fetch实现网络请求 /* fetch 是一个封装程度更高的网络API, 使用了Promise* Promise 是异步编程的一种解决方案* Promise 对 ...