简单易懂的 Go 函数带图教程
![3c95db1e2662975510312f068a622bbf.png](https://i-blog.csdnimg.cn/blog_migrate/95aa9e3d0a0c15959df52f3ed088f521.jpeg)
注意:该教程仅介绍 Go 函数,不包括:可变参数、延迟函数、外部函数、方法、HTTP、封包编码等。
什么是函数?
函数是一个独立的,可以被重用的,可以一次又一次运行的代码块。函数可以有输入参数,也可以有返回值输出。
为什么我们需要函数?
- 增加可读性、可测试性和可维护性
- 使代码的不同部分可以分别执行
- 可以由小模块组成新的模块
- 可以向类型增加行为
- 便于组织代码
- 符合 DRY 原则
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
![422128143425c909ef61264f6fe8cdf1.png](https://i-blog.csdnimg.cn/blog_migrate/5db3368f703e76b8be5f5c18a68e4d78.jpeg)
声明了一个函数 “Len”,输入参数为 “s”,类型为 “string”,返回值类型为 “int”。
✪ 首先:声明一个 Len 函数
func Len(s string) int { return utf8.RuneCountInString(s)}
✪ 然后:通过它的名字调用它
Len("Hello world ")
在线运行程序
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
输入参数和返回值类型
输入参数被用来把数据传递给函数。返回值类型被用来从函数中返回数据。从函数中返回的数据被称为“返回值”。
![d6c3125f14be878bd0b97f2a1d45acd3.png](https://i-blog.csdnimg.cn/blog_migrate/5a28ced69cb354772f0386d1ff10d271.jpeg)
采用一个名为 “s” 的 string 类型“输入参数”,并返回一个“返回值类型”为 int 的没有名字的返回值。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
![90009d7cb18ff500315ac2e14d5c6f58.png](https://i-blog.csdnimg.cn/blog_migrate/f1f0ef63bd5cdbcde6bdbc13acf4bede.jpeg)
函数签名就是一个函数的类型 -- 由输入参数类型和返回值类型组成。
func jump()// 签名:func()func Len(s string) int// 签名:func(string) intfunc multiply(n ...float64) []float64// 签名:func(...float64) []float64
Go 语言中的函数是一等公民,可以被任意赋值传递。
flen := Lenflen("Hello!")
在线运行程序
一个函数签名的示例代码。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
![6ec458e08220dbf653d03f362548e65e.png](https://i-blog.csdnimg.cn/blog_migrate/94a91cbd30f797c2c75814589bfc6bef.jpeg)
当一个函数被调用时,它的主体将以提供的输入参数运行。如果函数声明了至少一个返回值类型,那么函数将会返回一个或多个返回值。
你可以直接从 RuneCountInString 函数返回,因为它也返回一个 int。
func Len(s string) int { return utf8.RuneCountInString(s)}lettersLen := Len("Hey!")
这个函数使用表达式作为返回值。
func returnWithExpression(a, b int) int { return a * b * 2 * anotherFunc(a, b)}
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
函数块
每一组括号都会创建一个新的函数块,任何在函数块内声明的标识符只在该函数块内可见。
const message = "Hello world "func HelloWorld() { name := "Dennis" message := "Hello, earthling!"}
HelloWorld()/*★ message 常量在这里可见。★ 在函数内的变量 name 在这里不可见。★ 在函数内被隐藏的变量 message 在这里不可见。*/
在线运行程序
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
现在,让我们看看输入参数和返回值类型不同风格的声明方式。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
![304918b7b43153f95560afcff15c46c2.png](https://i-blog.csdnimg.cn/blog_migrate/3d67d0e3ce9998e4a1e0b13ae9af3db9.jpeg)
声明一个类型为 “String” 的输入参数 “s”,和一个整数返回值类型。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
![7149a9121b250cf4acc8fa351b4da253.png](https://i-blog.csdnimg.cn/blog_migrate/5efeba2db1b9a98487352c36b7d60633.jpeg)
一个函数的输入参数和返回值类型就像变量一样起作用。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
Niladic 函数
Niladic 函数不接受任何输入参数。
func tick() {
fmt.Println( time.Now().Format( time.Kitchen ) )
}
tick()
// Output: 13:50pm etc.
在线运行程序
如果一个函数没有返回值,你可以省略返回值类型和 return 这个关键字。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
Singular 函数
func square(n int) int { return n * n}square(4)// Output: 16
当函数只返回一个返回值时,不要使用括号。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
多个输入参数和返回值
func scale(width, height, scale int) (int, int) { return width * scale, height * scale}w, h := scale(5, 10, 2)// Output: w is 10, h is 20
多个返回值类型应该用圆括号括起来。
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
自动类型分配
Go 语言会自动为前面的参数声明类型。
![31390a206b90f7e566e4cc27d33db8a6.png](https://i-blog.csdnimg.cn/blog_migrate/62d19f4e2a94d7753db597498de5e80a.jpeg)
这些声明是一样的:
func scale(width, height, scale int) (int, int)func scale(width int, height int, scale int) (int, int)
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
错误值
一些函数通常会返回错误 -- 多个返回值让这使用很方便。
func write(w io.Writer, str string) (int, error) { return w.Write([]byte(s))}write(os.Stdout, "hello")// Output: hello
从 Write 函数直接返回和返回多个返回值类型是相同的。因为它也返回一个 int 和一个错误值。
func write(w io.Writer, str string) (int, error) { n, err := w.Write([]byte(s)) return n, err}
如果一切正常,你可以直接返回 nil 作为结果:
func div(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("divide by zero") } return a / b, nil}r, err := div(-1, 0)// err: divide by zero
![1e039c26ea2456c9b73c05d2b6cf86a8.png](https://i-blog.csdnimg.cn/blog_migrate/d7540578f520256cb0ec82ef252d7e64.jpeg)
丢弃返回值
你可以使用下划线来丢弃返回值。
/*假设我们有如下函数:*/func TempDir(dir, prefix string) (name string, err error)
丢弃错误返回值(第 2 个返回值):
name, _ := TempDir(