首页 > 其他分享 >Go 的函数,方法和接口

Go 的函数,方法和接口

时间:2024-01-30 21:11:07浏览次数:19  
标签:return 函数 float64 fmt 接口 Println func Go

函数 (function)

  • 函数可以没有参数或者接受多个参数。

  • 当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它都可以省略。

func add(x, y int) int {
    return x + y
}
  • 函数(或者变量)的名称以大写字母开头时,它就是已导出的。

  • 函数可以返回任意数量的字符串。

func swap(x, y string) (string, string) {
    return y, x
}
  • 函数的返回值可以被命名,它们会被视作在函数顶部定义的变量,没有参数的 return 返回已经被命名的返回值。
func division(dividend, divisor int) (quotient, remainder int) {
    quotient = dividend / divisior
    remainder = dividend - quotient * divisor
    return
}
  • 函数也是值,也可以用作函数的参数和返回值。
// conpute 接受一个函数作为参数
// 调用 conpute 时传入不同的函数,返回对3和4作不同的操作的结果
func conpute(fn func(float64, float64) float64) float64 {
  return fn(3, 4)
}

函数的闭包 (closure)

  • A closure is a record storing a function together with an environment.

  • 闭包是由函数和环境组合而成的。闭包保存和记录了它产生时的外部环境——它的函数体之外的变量,并且可以访问和修改这些变量。

  • 在闭包实际实现的时候,往往通过调用一个外部函数返回其内部函数来实现的。用户得到一个闭包,也等同于得到了这个内部函数,每次执行这个闭包就等同于执行内部函数。

  • 如果外部函数的变量可见性是 local 的,即生命周期在外部函数结束时也结束的,那么闭包的环境就是封闭的。反之,那么闭包其实不再封闭,全局可见的变量的修改,也会对闭包内的这个变量造成影响。

package main

import "fmt"

func test_1(x int) func() {
	return func() {
		x++
		fmt.Println(x)
	}
}

func test_2(x int) func() {
	sum := 0
	return func() {
		sum += x
		fmt.Println(x, sum)
	}
}

func test_3(x int) func(int) int {
	sum := 0
	return func(y int) int {
		sum += x * y
		return sum
	}
}

func main() {
	test_1(1)()

	test_2(1)()

    // 每个闭包事实上有着不同的外部环境
    // 即:对每个 for 循环,都会新建一个 test_3()
    // 所以每个闭包绑定的是不同的 sum 变量
	for i := 0; i < 5; i++ {
		fmt.Printf("%d ", test_3(1)(i))
	}
	fmt.Println()

    // 每个闭包的外部环境相同(tmp)
    // 即 for 循环中的闭包绑定的是同一个 sum 变量
	tmp := test_3(1)
	for i := 0; i < 5; i++ {
		fmt.Printf("%d ", tmp(i))
	}
	fmt.Println()
}

上面的程序输出结果是:

2
1 1
1 1
0 1 2 3 4 
0 1 3 6 10

方法 (method)

  • Go 没有类,不过可以为结构体类型定义方法。方法就是一类带特殊的接收者参数的函数。方法接收者在它自己的参数列表内,位于 func 关键字和方法名之间。(非结构体类型也可以定义方法)
type Vertex struct {
	X, Y float64
}

func (v Vertex) distance() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
  • 方法并不能修改指针接收者的值。只有指针接收者的方法能够修改接收者指向的值。(在这种情况下,方法也没有修改接收者的值——指针的内容,只是修改了指针指向的值,和用指针作为参数是一样的)

  • 在很多意义上,方法的接收者和普通的参数是一样的。如果不使用指针。

  • 不过,带指针参数的函数必须接受一个指针,而以指针为接受者的方法被调用时,接受者接收者既能为值又能为指针。

package main

import "fmt"

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Move_1(dx, dy float64) {
	v.X += dx
	v.Y += dy
}

func (v Vertex) Move_2(dx, dy float64) {
	v.X += dx
	v.Y += dy
}

func Move_3(v *Vertex, dx, dy float64) {
	v.X += dx
	v.Y += dy
}

func Move_4(v Vertex, dx, dy float64) {
	v.X += dx
	v.Y += dy
}

func main() {
	var v Vertex
	v.X = 0
	v.Y = 0.
	v.Move_1(1, 1)
	fmt.Println(v.X, v.Y)
    p := &v
	p.Move_1(1, 1)
	fmt.Println(v.X, v.Y)
	v.Move_2(1, 1)
	fmt.Println(v.X, v.Y)
	Move_3(&v, 1, 1)
	fmt.Println(v.X, v.Y)
	Move_4(v, 1, 1)
	fmt.Println(v.X, v.Y)
}

上面的程序输出结果是:

1 1
2 2
2 2
3 3
3 3

接口 (interface)

  • 接口是一组方法签名的集合,接口类型的变量可以保存任何实现了这些方法的值。

  • Go 语言中的接口是隐式实现的,也就是说,如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口。没有 implements 关键字。

type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

type Abser interface {
	Abs() float64
}

func main() {
	var a Abser
	f := MyFloat(-math.Sqrt2)
	v := Vertex{3, 4}

	a = f  // MyFloat 实现了 Abs()
	a = &v // *Vertex 实现了 Abs()
}
  • 指定了零个方法的接口值被称为空接口,可以保存任何类型的值(因为每个类型都至少实现了零个方法)。空接口被用来处理未知类型的值。

  • 在内部,接口值可以看做包含值和具体类型的元组,类型断言提供了访问接口值底层具体值的方式。

package main

import "fmt"

func main() {
	var i interface{} = "hello"

    // 该语句断言接口值 i 保存了具体类型 string,
    // 并将其底层类型为 string 的值赋予变量 s。
    // 若 i 并未保存 string 类型的值,该语句就会触发 panic。
	s := i.(string)
	fmt.Println(s)

    // 为了判断一个接口值是否保存了一个特定的类型,
    // 类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。
    // 若 i 保存了一个 string,那么 s 将会是其底层值,而 ok 为 true。
    // 否则,ok 将为 false 而 s 将为 T 类型的零值,程序并不会产生 panic。
	s, ok := i.(string)
	fmt.Println(s, ok)

	f, ok := i.(float64)
	fmt.Println(f, ok)

	f = i.(float64) // 报错 (panic)
	fmt.Println(f)
}

上面的程序输出结果是:

hello
hello true
0 false
panic: interface conversion: interface {} is string, not float64
......

标签:return,函数,float64,fmt,接口,Println,func,Go
From: https://www.cnblogs.com/tea-in-the-snow/p/17997981

相关文章

  • go log/slog: package log/slog is not in GOROOT
    安装irisv12版本需要Golang>=1.21gogetgithub.com/kataras/iris/[email protected]/kataras/iris/v12importsgithub.com/kataras/gologimportslog/slog:packagelog/slogisnotinGOROOT(/usr/local/go/src/log/slog)参考链接:https://go.de......
  • 在RunnerGo测试平台中做WebSocket、Dubbo、TCP/IP接口测试
    大家好,RunnerGo作为一款一站式测试平台不断为用户提供更好的使用体验,最近得知RunnerGo新增对,WebSocket、Dubbo、TCP/IP,三种协议API的测试支持,本篇文章跟大家分享一下使用方法。WebSocket协议WebSocket是一种在单个TCP连接上进行全双工通信的API技术。相比于传统的HTTP请求,We......
  • Apipost接口用例怎么用
    在研发过程中,研发同学希望有一个独立的管理窗口能对调试完的接口进行自测,且不影响源接口数据。而测试同学则希望在做完测试后,可以把测试的数据给保存成测试用例,方便下一次测试的时候能够快速调用。Apipost接口用例功能就是为此而设计,在接口用例页面可以根据需求创建多个测试用例,创......
  • powershell param : 无法将“param”项识别为 cmdlet、函数、脚本文件或可运行程序的
    前言全局说明powershellparam:无法将“param”项识别为cmdlet、函数、脚本文件或可运行程序的名称。一、源码echo"脚本启动"param($age,$address="USA",$name)Write-Host"Name:$name"Write-Output"Address:$address"Write-Output"Age:$age&qu......
  • 浅谈闭包(防抖,节流,函数柯里化)
    闭包参考文章谈谈你对闭包的理解概念:(1)闭包就是引用了另一个函数的变量的函数(2)闭包一般是函数嵌套,一个函数返回另外一个函数,内部函数访问外部函数的变量就形成了一个闭包作用(优点):(3)闭包的优点是可以私有化变量,将变量私有化到函数内部,并在私有化的基础上进行数据保持......
  • epoll_ctl函数
    目录函数简介低层实现逻辑函数简介/*Manipulateanepollinstance"epfd".Returns0incaseofsuccess,-1incaseoferror(the"errno"variablewillcontainthespecificerrorcode)The"op"parameterisoneoftheEPOLL_CTL_*......
  • Apipost接口用例怎么用
    在研发过程中,研发同学希望有一个独立的管理窗口能对调试完的接口进行自测,且不影响源接口数据。而测试同学则希望在做完测试后,可以把测试的数据给保存成测试用例,方便下一次测试的时候能够快速调用。Apipost接口用例功能就是为此而设计,在接口用例页面可以根据需求创建多个测试用例......
  • 在RunnerGo测试平台中做WebSocket、Dubbo、TCP/IP接口测试
    大家好,RunnerGo作为一款一站式测试平台不断为用户提供更好的使用体验,最近得知RunnerGo新增对,WebSocket、Dubbo、TCP/IP,三种协议API的测试支持,本篇文章跟大家分享一下使用方法。WebSocket协议WebSocket是一种在单个TCP连接上进行全双工通信的API技术。相比于传统的HTTP请......
  • epoll_create函数
    目录函数简介低层实现逻辑epoll_create与epoll_create1函数的区别函数简介/*Createsanepollinstance.Returnsanfdforthenewinstance.The"size"parameterisahintspecifyingthenumberoffiledescriptorstobeassociatedwiththenewinstance.......
  • epoll_wait函数
    目录函数实现低层实现逻辑函数实现/*Waitforeventsonanepollinstance"epfd".Returnsthenumberoftriggeredeventsreturnedin"events"buffer.Or-1incaseoferrorwiththe"errno"variablesettothespecificerrorcode.The......