本篇主要介绍Golang里面的函数、方法以及接口。 首先,说一下函数(function)和方法(method)的区别?其实长的都一样,只不过方法是属于某个对象(或结构体),只有对象自己能调用,而函数则像是公共的,谁都可以调用。
1.函数(function)
在Go里面,函数是一等公民,main函数就是Go程序的执行入口,但是main函数无法被调用。Go里面函数不仅仅可以被调用,而且还可以当作一种类型,所以很容易就可以实现函数式编程。
package mainimport ("fmt""github.com/pkg/errors")func main() {fmt.Printf("Hello World!\n")say("12345")//无返回值函数result := Add(1, 2)//有返回值函数fmt.Printf("%d\n", result)i, err := divide(12, 2)//多返回值iferr != nil {panic(err)}fmt.Printf("%d\n", i)}func say(something string) {fmt.Printf("%s\n", something)}func Add(a, bint)int{returna + b}func divide(a, bint) (int, error) {ifb == 0 {return0, errors.New("can not divide by zero")}returna / b, nil}//运行结果:/**Hello World!1234536*/在Go里面定义函数采用func关键字,语法基本上和大部分语言一致,需要特别说明的是Go的函数支持多返回值,这一点特别方便。
在Go里面还有一个隐性约束,如果函数名、结构体成员名、变量名首字母大写则意味着是公开的,可以被其它包引用,否则只能在当前包内使用。
Go里面也有匿名函数(又被称为闭包函数),下面是Go函数一个闭包用法:
package mainimport ("fmt")type addType func(aint)intfunc main() {i := add()fmt.Printf("%T\n", i)fmt.Printf("%v", i(1))}func add() addType {returnfunc(aint)int{returna + 1}}//运行结果:/**main.addType2*/说到函数就不得不提Go里面一个非常特殊的函数 init(), 这个函数相当于OOP编程里面的构造函数,但是它并不是针对某个类或结构体的,它是一个包级别的初始化函数。
所谓包级别是指当你使用到一个包里面的文件的时候这个函数就会自动执行,这个包里面可能有多个go文件,每个go文件都有可能定义了init函数,如果定义了,那么go就会依次执行init函数,其执行顺序取决于import的顺序。
说到这,借用一张非常经典的Go包加载顺序图:
在项目里面我们经常会使用init函数去做一些起步工作,比如初始化数据库连接池、加载配置文件。
2.方法(method)
方法和函数基本上一样,只不过它是针对某个结构体而言,说白了,方法是属于某个结构体的。
package mainimport"fmt"func main() {g := goods{name:"苹果"}//初始化结构体g.say()gName := g.getGoodsName()//调用结构体方法fmt.Printf("%s\n", gName)}type goodsstruct{namestring}func (goods) say() {fmt.Printf("nothing\n")}func (g goods) getGoodsName()string{returng.name}关于结构体的知识这里简单说下,结构体(struct) 我们可以理解为OOP编程里面的类(class),Go并不是一个完全OOP的语言,但是这并不妨碍我们使用OOP的编程思想。
大家可以看到方法有2个小括号,我们把方法前面那个小括号里面的参数称之为接受者,接受者决定了这个方法属于哪个结构体。
3.接口(interface)
说到OOP不得不说到接口,Go里面的接口和传统OOP编程里面的接口稍微有一些差异,更加灵活,不需要使用 implements 关键字,而是一种隐式的实现。
package mainimport"fmt"func main() {cache := MemCache{data: map[string]string{}}test(cache)}//定义一个Cache接口,只要实现了这2个方法的struct都算实现了该接口type Cache interface {Get(key string) stringSet(key string, value string)}//一个内存缓存type MemCachestruct{data map[string]string}func (m MemCache) Get(key string) string {returnm.data[key]}func (m MemCache) Set(key string, value string) {m.data[key] = valuefmt.Printf("set %s to %s\n", key, value)}//测试,它的参数声明需要的是一个实现了Cache接口的对象func test(cache Cache) {cache.Set("v1","缓存内容")result := cache.Get("v1")fmt.Printf("get v1: %s\n", result)}Go这种形式被称为duck type,所谓鸭子类型说的是:只要走起路来像鸭子、叫起来也像鸭子,那么就可以把它当作鸭子。