golang的函数和接口以及interface [golang学习笔记3]

golang 专栏收录该内容
8 篇文章 0 订阅

1.函数

1.1 函数定义 

Go 语言函数定义格式如下:

func function_name( [parameter list] ) ([return_types list]) {
   函数体
}

函数定义解析:

func:函数由 func 开始声明
function_name:函数名称,函数名和参数列表一起构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指                            定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types list:返回类型列表。当函数不需要返回值时,return_types list不是必须的,可以省略;当函数具有多个返回值,必须                               用括号()把函数返回类型列表包含起来;如果只有一个返回值,可以省略括号。
函数体:函数定义的代码集合。

以下提供一种具名的参数示例:

//具名函数
func add(a, b int) int {
	return a + b
}

1.2 匿名函数

匿名函数有两种使用方式
①在定义匿名函数的时候就可以直接使用(这种方式只使用一次)

package main

//具名函数
func add(a, b int) int {
	return a + b
}

func main() {
	a := 1
	b := 2
	println("a = 1, b = 2")
	sum := func(a1, b1 int) int {
		return a1 + b1
	}(a, b)    //这里()需要传自定义的参数类型数据
	println("func(a,b)=", sum)
	
	//匿名函数当参数
	sum = add(a, func(a, b int) int {
		return a + b
	}(a, b))
	println("add(a, func(a,b))=", sum)
}

②将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数

这种匿名函数和具名函数基本类似。

package main

//具名函数
func add(a, b int) int {
	return a + b
}
//全局匿名函数
var add1 = func(a, b int) int {
	return a + b
}
func main() {
	a := 1
	b := 2
	println("a=1, b = 2")

	println("add(a,b)=", add(a, b))

	println("add1(a,b)=", add1(a, b))

	//局部匿名函数, 注意和全局匿名函数的区别,只在定义的作用域内使用
	var sub = func(a, b int) int {
		return a - b
	}
	println("sub(a,b)=", sub(a, b))
}

1.3 可变参数

可变参数就是一个占位符,你可以将1个或者多个参数赋值给这个占位符,这样不管实际参数的数量是多少,都能交给可变参数来处理,我们看一下可变参数的声明:

func func_name(a int, more ...interface{}) (n int, err error)
func func_name(more ...interface{}) (n int, err error)

可变参数使用name ...Type的形式声明在函数的参数列表中,而且需要是参数列表的最后一个参数,这点与其他语言类似;

值得注意,golang的可变参数不需要强制绑定参数的出现。

可变参数在函数中将转换为对应的[]Type类型,所以我们可以像使用slice(切片)时一样来获取传给函数的参数们;

package main

//可变参数
func addEx(more ...int) int {
	a := 0
	for _, v := range more {
		a += v
	}
	return a
}

func main() {
	println("addEx(...)=", addEx())
	println("addEx(...)=", addEx(1))
	println("addEx(...)=", addEx(1, 2))
	println("addEx(...)=", addEx(1, 2, 3))
	println("addEx(...)=", addEx(1, 2, 3, 4))
}

2. 方法

go方法:在函数的func和函数名间增加一个特殊的接收器类型,接收器可以是结构体类型或非结构体类型。接收器可以在方法内部访问。创建一个接收器类型为Type的methodName方法。

func (t Type) methodName(parameter list) (return_type list) {
    函数体
}

Go语言的方法关联到类型的,这样可以在编译阶段完成方法的静态绑定。

我们可以给任何自定义类型添加一个或多个方法。每种类型对应的方法必须和类型的定义在同一个包中,因此是无法给 int 这类内置类型添加方法的(因为方法的定义和类型的定义不在一个包中)。但是,我们可以类似使用 type retype_name type_name重定义类型来实现方法,类似如下示例重定义int 为 myint 来实现方法。对于func的前置参数可以是重定义的类型或者自定义的struct。注意:对于给定的类型,每个方法的名字必须是唯一的,同时方法和函数一样也不支持重载。

package main

type myint int

type basictype struct {
}

func (c *myint) add(a, b int) int {
	return a + b
}

func (c *myint) sub(a, b int) int {
	return a - b
}


func main() {
	a := 7
	b := 3
	var pa *myint
	println("add(a,b)=", pa.add(a, b))
	println("sub(a,b)=", pa.sub(a, b))
}

方法是由函数演变而来,只是将函数的第一个对象参数移动到了函数名前面了而已。因此我们依然可以按照原始的过程式思维来使用方法。通过叫方法表达式的特性可以将方法还原为普通类型的函数。

3.接口

Go的接口类型是对其它类型行为的抽象和概括,

因为接口类型不会和特定的实现细节绑定在一起,通过这种抽象的方式我们可以让对象更加灵活和更具有适应能力。很多面向对象的语言都有相似的接口概念,比如java和c++的class概念,但Go语言中接口类型的独特之处在于它是满足隐式实现的鸭子类型。所谓鸭子类型说的是:只要走起路来像鸭子、叫起来也像鸭子,那么就可以把它当作鸭子。所以我们可以隐式实现类似接口的结构,如下。

/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
   /* variables */
}

/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* 方法实现*/
}

利用接口,我们就可以实现面向对象语言的多态的概念,接口实现示例如下: 

package main

import (
	"fmt"
)

type Phone interface {
	call()
}

type MiPhone struct {
}

func (xiaomi MiPhone) call() {
	fmt.Println("I am xiaomi.")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
	fmt.Println("I am iPhone.")
}

func main() {
	var phone Phone

	phone = new(MiPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()

}

后续补充。。。

4. 闭包

在学习defer时碰到一个将闭包讲的比较直白的,就添加在这里了

func Inc() (v int) { 
   
    defer func(){ 
        v++ 
    } () 

    return 42 
} 

其中 defer 语句延迟执行了一个匿名函数,因为这个匿名函数捕获了外部函数的局部变量 v ,这种函数我们一般叫闭包。闭包对捕获的外部变量并不是传值方式访问,而是以引用的方式访问。 有兴趣的可以了解下这个,并试运行下结果是否是和你猜想的一致。

新手学习,有错请指正,谢谢。

参考:

https://www.runoob.com/go/go-interfaces.html 

https://www.jianshu.com/p/6fa443a19267

https://www.cnblogs.com/saryli/p/10092010.html

 

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值