Go语言指南-6.1 介绍

作者: Golang资深开发

6.1 介绍

每一个程序都包含很多的函数:函数是基本的代码块。 Go是编译型语言,所以函数编写的顺序是无关紧要的;鉴于可读性的需求,最好把 main() 函数写在文件的前面,其他函数按照一定逻辑顺序进行编写(例如函数被调用的顺序)。

编写多个函数的主要目的是将一个需要很多行代码的复杂问题分解为一系列简单的任务(那就是函数)来解决。而且,同一个任务(函数)可以被调用多次,有助于代码重用。

(事实上,好的程序是非常注意DRY原则的,即不要重复你自己(Don't Repeat Yourself),意思是执行特定任务的代码只能在程序里面出现一次。)

当函数执行到代码块最后一行(} 之前)或者 return 语句的时候会退出,其中 return 语句可以带有零个或多个参数;这些参数将作为返回值(参考 [第 6.2 节])供调用者使用。简单的 return 语句也可以用来结束 for 死循环,或者结束一个协程(goroutine)。 Go 里面有三种类型的函数:

  • 普通的带有名字的函数
  • 匿名函数或者lambda函数(参考 [第 6.8 节])
  • 方法(Methods,参考 [第 10.6 节])

除了main()、init()函数外,其它所有类型的函数都可以有参数与返回值。函数参数、返回值以及它们的类型被统称为函数签名。

作为提醒,提前介绍一个语法:

这样是不正确的 Go 代码:

   func g()
   {
   }

它必须是这样的:

   func g() {
   }

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

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

Functionpack1 包里面的一个函数,括号里的是被调用函数的实参(argument):这些值被传递给被调用函数的形参 (parameter,参考 [第 6.2 节])。函数被调用的时候,这些实参将被复制(简单而言)然后传递给被调用函数。函数一般是在其他函数里面被调用的,这个其他函数被称为调用函数(calling function)。函数能多次调用其他函数,这些被调用函数按顺序(简单而言)执行,理论上,函数调用其他函数的次数是无穷的(直到函数调用栈被耗尽)。

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

示例 6.1 [greeting.go] $eBook-examples-chapter_6-greeting.go

   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))

函数重载(function overloading)指的是可以编写多个同名函数,只要它们拥有不同的形参与/或者不同的返回值,在 Go 里面函数重载是不被允许的。这将导致一个编译错误:

   funcName redeclared in this book, previous declaration at lineno

Go 语言不支持这项特性的主要原因是函数重载需要进行多余的类型匹配影响性能;没有重载意味着只是一个简单的函数调度。所以你需要给不同的函数使用不同的名字,我们通常会根据函数的特征对函数进行命名(参考 [第 11.12.5 节])。

如果需要申明一个在外部定义的函数,你只需要给出函数名与函数签名,不需要给出函数体:

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

函数也可以以申明的方式被使用,作为一个函数类型,就像:

   type binOp func(int, int) int

在这里,不需要函数体 ``。

函数是一等值(first-class value):它们可以赋值给变量,就像 add := binOp 一样。

这个变量知道自己指向的函数的签名,所以给它赋一个具有不同签名的函数值是不可能的。

函数值(functions value)之间可以相互比较:如果它们引用的是相同的函数或者都是 nil 的话,则认为它们是相同的函数。函数不能在其它函数里面声明(不能嵌套),不过我们可以通过使用匿名函数(参考 [第 6.8 节])来破除这个限制。

目前 Go 没有泛型(generic)的概念,也就是说它不支持那种支持多种类型的函数。不过在大部分情况下可以通过接口(interface),特别是空接口与类型选择(type switch,参考 [第 11.12 节])来实现相似的功能。使用这些技术将导致代码更为复杂、性能更为低下,所以在非常注意性能的的场合,最好是为每一个类型单独创建一个函数,而且代码可读性更强。

链接

文章列表

更多推荐

更多
  • Go安全-二、Go 编程语言 Go 语言规范,The Go playground,Go之旅,关键词,评论,类型,Boolean,数字的,通用编号,具体数字,无符号整数,Signed integers,浮点数,其他数字类型,一串, 在深入研究使用 GO 进行安全
    Golang资深开发

  • Go安全-三、使用文件 File basics,创建空文件,截断文件,获取文件信息,重命名文件,删除文件,打开和关闭文件,检查文件是否存在,检查读写权限,更改权限、所有权和时间戳,硬链接和符号链接,读写,复制文件,Seeking positions in a
    Golang资深开发

  • Go安全-一、Go 安全简介 About Go,Go语言设计,The History of Go,收养与社区,关于Go的常见批评,Go工具链,Go吉祥物,学习Go,为什么要用Go?,为什么使用 Go 进行安全保护?,为什么不使用 Python 呢?,为什么不使用 J
    Golang资深开发

  • Go安全-零、前言 这本书是给谁的,这本书涵盖的内容,充分利用这本书,下载示例代码文件,使用的惯例,联系,评论, 本书涵盖了 Go 编程语言,并解释了如何将其应用于网络安全行业。所涵盖的主题对于红色和蓝色团队、希望编写安全代码的开发人员以及希望保护其
    Golang资深开发

  • Go安全-十、爬虫 爬虫基础,使用 strings 包在 HTTP 响应中查找字符串,使用正则表达式查找页面中的电子邮件地址,从 HTTP 响应中提取 HTTP 头,使用 HTTP 客户端设置 Cookie,在 web 服务器上查找未列出的文件,更改请求的
    Golang资深开发

  • Go安全-六、密码学 散列,散列小文件,散列大文件,安全地存储密码,加密,加密安全伪随机数生成器CSPRNG,Symmetric encryption,AES,非对称加密,生成公钥和私钥对,对邮件进行数字签名,验证签名,TLS,生成自签名证书,创建证书签名请
    Golang资深开发

  • Go安全-七、安全 Shell(SSH) 七、安全 ShellSSH使用 GoSSH 客户端,Authentication methods,使用密码进行身份验证,使用私钥进行身份验证,验证远程主机,通过 SSH 执行命令,启动交互式 shell, 安全外壳(S
    Golang资深开发

  • Go安全-八、暴力破解 Brute forcing HTTP basic authentication,强制使用 HTML 登录表单,强制 SSH,Brute forcing database login, 蛮力攻击,也称为穷举密钥攻击,是指您尝试输入的
    Golang资深开发

  • Go安全-十三、实现漏洞利用 交叉编译,创建绑定壳,创建反向绑定壳,创建 web shell,查找可写文件,更改文件时间戳,更改文件权限,更改文件所有权, 后利用是指渗透测试的一个阶段,其中一台机器已经被利用,代码执行可用。主要任务通常是保持持久性,以便您可以
    Golang资深开发

  • Go安全-十四、总结 重述您所学的主题关于 Go 用法的更多思考,我希望你能从这本书中得到什么,了解法律、道德和技术界限,从这里到哪里去,获得帮助和学习更多,重述您所学的主题到目前为止,在本书中,我们讨论了许多关于Go和信息安全的话题。所涵盖
    Golang资深开发

  • 近期文章

    更多
    文章目录

      推荐作者

      更多