Go语言的函数

《QGIS快速入门与应用基础》161:面要素顶点编辑与形状调整 本文系统讲解了QGIS中面要素顶点编辑与形状调整的核心操作。首先明确了顶点编辑的适用场景与核心概念,强调需满足图层类型、编辑模式、要素选择等六大前提。详细介绍了编辑顶点工具(F2键)的激活路径及配套辅助工具,通过耕地地块修正案例,分步骤演示顶点移动、添加(双击/工具栏)、删除(Delete键)三大基础操作。同时提供捕捉工具开启、画布缩放等实用技巧,帮助用户高效完成面要素的精细化调整,解决实际工作中的形状偏差问题。全文图文结合,步骤清晰,适合GIS新手快速掌握面要素编辑的核心技能。 阅读详情

Go语言支持普通函数、匿名函数和闭包。

声明函数

普通函数的声明形式如下:

func 函数名 (参数列表) (返回参数列表) {

        函数体

        return

}

Go语言函数的基本组成是:关键字func、函数名、参数列表、返回值 、函数体和返回语句。

func FunctionName Signature [FunctionBody]

func为定义函数的关键字,FunctionName为函数名,Signature为函数签名,FunctionBody为函数体。函数签名由函数参数、返回值以及它们的类型组成。

一个完整的函数声明结构格式如下:

func funName(input1 type1, input2 type2)(output1 type1 output2 type2){
    //逻辑代码
    return value1,value2    //返回多值
}

Go语言函数不支持嵌套(nested)、重载(overload)和默认参数(default parameter)。

返回单个值的代码如下:

package main

import(
  "fmt"
)
func isEven(i int) bool{
  return i%2==0
}
func main(){
  fmt.Printf("%v\n",isEven(1))
  fmt.Printf("%v\n",isEven(2))
}

运行结果如下:

false
true

返回多个值的代码如下:

package main

import(
  "fmt"
)
func getPrize()(int,string){
  i:=2
  s:="goldfish"
  return i,s
}
func main(){
  quantity,prize:=getPrize()
  fmt.Printf("You won %v %v\n",quantity,prize)
}

运行结果如下:

You won 2 goldfish

定义不定参数函数的代码如下:

package main

import(
  "fmt"
)
func sumNumbers(numbers...int)int{
  total:=0
  for _,number:=range numbers{
    total+=number
  }
  return total
}
func main(){
  result:=sumNumbers(1,2,3,4)
  fmt.Printf("The result is %v\n",result)
}

运行结果如下:

The result is 10

代码如下:

package main

import "fmt"

func MyPrintf(args ...interface{}) {
	for _, arg := range args {
		switch arg.(type) {
		case int:
			fmt.Println(arg, "is an int value.")
		case string:
			fmt.Println(arg, "is a string value.")
		case int64:
			fmt.Println(arg, "is an int64 value.")
		default:
			fmt.Println(arg, "is an unknown type.")
		}
	}
}

func main() {
	var v1 int = 1
	var v2 int64 = 234
	var v3 string = "hello"
	var v4 float32 = 1.234
	MyPrintf(v1, v2, v3, v4)
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go\main.go"
1 is an int value.
234 is an int64 value.
hello is a string value.
1.234 is an unknown type.

[Done] exited with code=0 in 1.146 seconds

使用具名返回值的代码如下:

package main

import(
  "fmt"
)
func sayHi()(x,y string){
  x="hello"
  y="world"
  return
}
func main(){
  fmt.Println(sayHi())
}

运行结果如下:

hello world

使用递归函数的代码如下:

package main

import(
  "fmt"
)
func feedMe(portion int, eaten int)int{
  eaten=portion+eaten
  if eaten>=5{
    fmt.Printf("I'm full! I've eaten %d\n",eaten)
    return eaten
  }
  fmt.Printf("I'm still hungry! I've eated %d\n",eaten)
  return feedMe(portion,eaten)
}
func main(){
  fmt.Println(feedMe(1,0))
}

运行结果如下:

I'm still hungry! I've eated 1
I'm still hungry! I've eated 2
I'm still hungry! I've eated 3
I'm still hungry! I've eated 4
I'm full! I've eaten 5
5

将函数作为值传递的代码如下:

package main

import(
  "fmt"
)
func anotherFunction(f func() string) string{
  return f()
}
func main(){
  fn:=func()string{
    return "function called"
  }
  fmt.Println(anotherFunction(fn))
}

运行结果如下:

function called

返回多个值的函数,代码如下:

package main

import (
	"fmt"
)

func swapNumber(a, b int) (int, int) {
	return b, a
}
func main() {
	fmt.Println(swapNumber(1, 2))
}

运行结果如下:

2 1

如果不需要函数的多个返回值,可以用下画线“_”字符来代替不需要赋值的变量,代码如下:

package main

import (
	"fmt"
)

func swapNumber(a, b int) (int, int) {
	return b, a
}
func main() {
	n1 := 1
	n2 := 2
	n3, _ := swapNumber(n1, n2)
	fmt.Println(n3)
}

运行结果如下:

2

空白标识符“_”自动丢弃掉。

多返回值,代码如下:

package main

import (
	"fmt"
)

func SumAndProduct(A, B int) (int, int) {
	return A + B, A * B
}

func main() {
	x := 3
	y := 4
	xPLUSy, xTIMESy := SumAndProduct(x, y)
	fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
	fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}

运行结果如下:

3 + 4 = 7
3 * 4 = 12

函数作为类型,代码如下:

package main

import (
	"fmt"
)

func isOdd(v int) bool {
	if v%2 == 0 {
		return false
	}
	return true
}
func isEven(v int) bool {
	if v%2 == 0 {
		return true
	}
	return false
}

type bool1Func func(int) bool	//声明一个函数类型
//函数作为一个参数使用
func filter(slice []int, f bool1Func) []int {
	var result []int
	for _, value := range slice {
		if f(value) {
			result = append(result, value)
		}
	}
	return result
}

func main() {
	slice := []int{3, 1, 4, 5, 9, 2}
	fmt.Println("slice= ", slice)
	odd := filter(slice, isOdd)		//函数当作值来传递
	fmt.Println("odd:", odd)
	even := filter(slice, isEven)	//函数当作值来传递。
	fmt.Println("even:", even)
}

运行结果如下:

slice=  [3 1 4 5 9 2]
odd: [3 1 5 9]
even: [4 2]

可变参数:

函数有着不定数量的参数在很多时候都会遇到。Go语言函数支持可变参数。需要定义函数使其接受变参:

func myfunc(arg ...int) {}

在Go语言中,函数的最后一个参数如果是...type的形式,那这个函数是一个变参函数,它可以处理变长的参数,而这个长度可以是0。注意的是在变参函数中,无论变参多少个,它们的类型全部都一样的。

代码如下:

package main

import (
	"fmt"
)

func main() {
	age := ageMinOrMax("min", 1, 3, 2, 0)
	fmt.Printf("年龄最小的是%d岁。\n", age)
	ageArr := []int{7, 9, 3, 5, 1}
	age = ageMinOrMax("max", ageArr...)
	fmt.Printf("年龄最大的是%d岁。", age)
}

func ageMinOrMax(m string, a ...int) int {
	if len(a) == 0 {
		return 0
	}
	if m == "max" {
		max := a[0]
		for _, v := range a {
			if v > max {
				max = v
			}
		}
		return max
	} else if m == "min" {
		min := a[0]
		for _, v := range a {
			if v < min {
				min = v
			}
		}
		return min
	} else {
		e := -1
		return e
	}
}

运行结果如下:

年龄最小的是0岁。
年龄最大的是9岁。

代码如下:

package main

import (
	"fmt"
)

func main() {
	ageArr := []int{7, 9, 3, 5, 1}
	f1(ageArr...)
}

func f1(arr ...int) {
	f2(arr...)
	fmt.Println("")
	f3(arr)
}

func f2(arr ...int) {    //f2(1,3,7,13)
	for _, char := range arr {
		fmt.Printf("%d ", char)
	}
}

func f3(arr []int) {    //f3([]int{1,3,7,13})
	for _, char := range arr {
		fmt.Printf("%d ", char)
	}
}

运行结果如下:

7 9 3 5 1 
7 9 3 5 1 

如果希望传递任意类型,可以指定类型为interface{},也就是接口。下面是Go语言标准库中fmt.Printf()的函数原型:

func Printf(format string, args ...interface{}){
    // ...
}

常用的Printf函数就是一个变参函数,而且不限制参数类型。用interface{}传递任意类型数据是Go语言的习惯用法。

匿名函数

匿名函数的例子:

func(x,y int) int {return x+y}(3,4)

fpluse:=func(x,y int) int {return x+y}

fplus(3,4)

代码如下:

package main

import (
	"fmt"
)

func main() {
	func(num int) int {
		sum := 0
		for i := 1; i <= num; i++ {
			sum += i
		}
		fmt.Println(sum)
		return sum
	}(100)
}

运行结果如下:

5050

闭包:(没看懂)

闭包允许调用定义在其它环境下的变量,可使得某个函数捕捉到一些外部状态。

一个闭包继承了函数声明时的作用域。

代码如下:

package main

import (
	"fmt"
)

func main() {
	fmt.Printf("%d\n", Add()(3))
	fmt.Printf("%d\n", Add2(6)(3))
}

//Add无参函数,返回值是一个匿名函数,匿名函数返回一个int类型的值
func Add() func(b int) int {
	return func(b int) int {
		return b + 2
	}
}

//Add2无参函数,返回值是一个匿名函数,匿名函数返回一个int类型的值
func Add2(a int) func(b int) int {
	return func(b int) int {
		return a + b
	}
}

运行结果如下:

5
9

代码如下:

package main

import (
	"fmt"
)

func main() {
	j := 5
	a := func() func() {
		i := 10
		return func() {
			fmt.Printf("i=%d j=%d\n", i, j)
		}
	}()
	a()
	j = 10
	a()
}

运行结果如下:

i=10 j=5
i=10 j=10

代码如下:

package main

import (
	"fmt"
)

func main() {
	var f = adder()
	fmt.Println(f(1))		//fmt.Println(adder()(1))
	fmt.Println(f(2))
	fmt.Println(f(3))
}
func adder() func(int) int {
	var x int
	return func(d int) int {
		fmt.Println("x = ", x, "d = ", d)
		x += d
		return x
	}
}

运行结果如下:

x =  0 d =  1
1
x =  1 d =  2
3
x =  3 d =  3
6

代码如下:

package main

import (
	"fmt"
)

func getSequence() func() int {
	i := 0
	return func() int {
		i++
		return i
	}
}

func main() {
	nextNumber := getSequence()
	fmt.Printf("%d ", nextNumber())
	fmt.Printf("%d ", nextNumber())
	fmt.Printf("%d ", nextNumber())

	nextNumber1 := getSequence()
	fmt.Printf("%d ", nextNumber1())
	fmt.Printf("%d ", nextNumber1())
}

运行结果如下:

1 2 3 1 2 

代码如下:

package main

import "fmt"

func main() {
	var j int = 5
	a := func() func() {
		var i int = 10
		return func() {
			fmt.Printf("i,j: %d, %d\n", i, j)
		}
	}()
	a()
	j *= 2
	a()
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go\main.go"
i,j: 10, 5
i,j: 10, 10

[Done] exited with code=0 in 1.282 seconds

递归函数:

递归,就是在运行的过程中调用自己。语法格式如下:

func recursion(){
    recursion()    //函数调用自身
}

func main(){
    recursion()
}

通过Go语言的递归函数实现阶乘运算,代码如下:

package main

import (
	"fmt"
)

func Factorial(n uint64) (result uint64) {
	if n > 0 {
		result = n * Factorial(n-1)
		return result
	}
	return 1
}

func main() {
	var i int = 15
	fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

运行结果如下:

15 的阶乘是 1307674368000

通过Go语言的递归函数实现斐波那契数列,代码如下:

package main

import (
	"fmt"
)

func fibonacci(n int) int {
	if n < 2 {
		return n
	}
	return fibonacci(n-2) + fibonacci(n-1)
}

func main() {
	var i int
	for i = 0; i < 10; i++ {
		fmt.Printf("%d\t", fibonacci(i))
	}
}

运行结果如下:

0	1	1	2	3	5	8	13	21	34	

内置函数:

close:用于管道通信。

len:用于返回某个类型的长度或数量(字符串、数组、切片、map和管道)。

cap:容量的意思,用于返回某个类型的最大容量(只能用于切片和map)。

new、make:均用于分配内存,不管new用于值类型和用户定义的类型,make用于内置引用类型(切片、map和管道)。new(T)分配类型T的零值并返回其地址,也就是指向类型T的指针。make(T)返回类型T的初始化之后的值。new()是一个函数,不要忘记它的括号。

copy、append:用于复制和连接切片。

panic、recover:两者均用于错误处理机制。

print、println:底层打印函数(部署环境中建议使用fmt包)。

complex、real imag:用于创建和操作复数。

函数进阶

参数传递机制:

Go语言的参数传递分为“按值传递”和“按引用传递”。

按值传递:传递的是参数的副本,函数接收参数副本后,使用变量的过程中可能对副本的值进行更改,但不会影响原来的变量。调用函数时修改参数的值,不会影响原来的实参的值,因此数值变化只作用在副本上。

按引用传递:如果让函数直接修改参数的值,而不是对参数的副本进行修改,就需要将参数的地址(变量名前面添加&符号)传递给函数。传递给函数数的是一个指针。

代码如下:(部分代码没看懂)

package main

import (
	"fmt"
)

func main() {
	x := 3
	fmt.Println("x =", x, "&x =", &x)

	y := add(x)
	fmt.Println("x =", x, "y =", y)

	z := addP(&x)
	fmt.Println("x =", x, "z =", z)
	fmt.Println("&x =", &x)
}

func add(a int) int {
	a++
	return a
}
func addP(a *int) int {
	*a++
	return *a
}

运行结果如下:

x = 3 &x = 0xc0000b2008
x = 3 y = 4
x = 4 z = 4
&x = 0xc0000b2008

代码如下:

package main

import (
	"fmt"
)

func main() {
	n := 0
	res := &n
	multiply(2, 4, res)
	fmt.Println("Result:", *res)
}

func multiply(a, b int, res *int) {
	*res = a * b
}

运行结果如下:

Result: 8

defer与跟踪

1.defer延迟语句

当函数执行到最后时(return语句执行之前),这些defer语句会按照“逆序”执行,最后该函数才退出。

defer的用途:在进行一些IO操作的时候,如果遇到错误,便需要提前返回,而返回之前应该关闭相应的资源,否则容易造成资源泄露等问题,defer语句就可以出色地解决这个问题。

如果多次调用defer,那么defer采用后进先出模式,代码如下:

package main

import (
	"fmt"
)

func main() {
	for i := 0; i < 5; i++ {
		defer fmt.Printf("%d ", i)
	}
}

运行结果如下:

4 3 2 1 0 

执行顺序,代码如下:

package main

import (
	"fmt"
)

func main() {
	fmt.Println("return:", a())
}
func a() int {
	var i int
	defer func() {
		i++
		fmt.Println("defer2:", i)
	}()
	defer func() {
		i++
		fmt.Println("defer1:", i)
	}()
	return i
}

运行结果如下:

defer1: 1
defer2: 2
return: 0

有名返回值的情况,代码如下:

package main

import (
	"fmt"
)

func main() {
	fmt.Println("return:", b())
}
func b() (i int) {
	defer func() {
		i++
		fmt.Println("defer2:", i)
	}()
	defer func() {
		i++
		fmt.Println("defer1:", i)
	}()
	return i
}

运行结果如下:

defer1: 1
defer2: 2
return: 2

多个defer语句的执行顺序为“逆序”,defer、return、返回值三者的执行逻辑应该是:defer最先执行一些收尾工作;然后return执行,return负责将结果写入返回值中;最后函数携带当前返回值退出。

defer、return、返回值三者的执行顺应应该是:return最先给返回值赋值;接着defer开始执行一些收尾工作;最后RET指令携带返回值退出函数。

代码如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	i, p := a()
	fmt.Println("return:", i, p, time.Now())
}

func a() (i int, p *int) {
	defer func(i int) {
		fmt.Println("defer3:", i, &i, time.Now())
	}(i)
	defer fmt.Println("defer2:", i, &i, time.Now())
	defer func() {
		fmt.Println("defer1:", i, &i, time.Now())
	}()
	i++
	func() {
		fmt.Println("print1:", i, &i, time.Now())
	}()
	fmt.Println("print2:", i, &i, time.Now())
	return i, &i
}

运行结果如下:

print1: 1 0xc0000b2008 2022-01-30 21:10:52.533105 +0800 CST m=+0.000106679
print2: 1 0xc0000b2008 2022-01-30 21:10:52.53332 +0800 CST m=+0.000321996
defer1: 1 0xc0000b2008 2022-01-30 21:10:52.533327 +0800 CST m=+0.000328647
defer2: 0 0xc0000b2008 2022-01-30 21:10:52.533104 +0800 CST m=+0.000106002
defer3: 0 0xc0000b20d8 2022-01-30 21:10:52.533337 +0800 CST m=+0.000338399
return: 1 0xc0000b2008 2022-01-30 21:10:52.533341 +0800 CST m=+0.000342559

2.跟踪

defer经常用于代码执行追踪。

代码如下:(代码没看懂)

package main

import (
	"fmt"
)

func main() {
	b()
}

func a() {
	defer un(trace("a"))
	fmt.Println("a的逻辑代码")
}
func b() {
	defer un(trace("b"))
	fmt.Println("b的逻辑代码")
	a()
}
func trace(s string) string {
	fmt.Println("开始执行", s)
	return s
}
func un(s string) {
	fmt.Println("结束执行", s)
}

运行结果如下:

开始执行 b
b的逻辑代码
开始执行 a
a的逻辑代码
结束执行 a
结束执行 b

错误与恢复

func panic(interface{})

func recover() interface {}

1.error

Go语言通过error接口实现错误处理的标准模式,该接口的定义如下:

type error interface{

        Error() string

}

2.panic

区别使用panic和error两种方式,导致关键流程出现不可修复性错误的情况使用panic,其它情况使用error。

3.recover

代码如下:

package main

import "fmt"

func main() {
	test()
}

func test() {
	defer func() {
		fmt.Println(recover())
	}()
	defer func() {
		func() {
			recover()
		}()
	}()
	defer fmt.Println(recover())
	defer recover()
	panic("发生错误")
}

运行结果如下:

<nil>
发生错误

代码如下:

package main

import "log"

func main() {
	test()
}

func test() {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("捕获到的异常:%v", r)
		}
	}()
	defer func() {
		panic("第二个错误")
	}()
	panic("第一个错误")
}

运行结果如下:

2022/01/30 21:50:02 捕获到的异常:第二个错误

代码如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	throwPanic(genErr)
}

func genErr() {
	fmt.Println(time.Now(), "正常的语句")
	defer func() {
		fmt.Println(time.Now(), "defer正常的语句")
		panic("第二个错误")
	}()
	panic("第一个错误")
}
func throwPanic(f func()) (b bool) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(time.Now(), "捕获到的异常:", r)
			b = true
		}
	}()
	f()
	return
}

运行结果如下:

2022-01-30 22:00:31.410723 +0800 CST m=+0.000230501 正常的语句
2022-01-30 22:00:31.411162 +0800 CST m=+0.000669905 defer正常的语句
2022-01-30 22:00:31.411185 +0800 CST m=+0.000692985 捕获到的异常: 第二个错误

示例:将“秒”解析为时间位置

代码如下:

package main

import (
	"fmt"
)

const (
	//定义每分钟的秒数
	SecondsPerMinute = 60

	//定义每小时的秒数
	SecondsPerHour   = SecondsPerMinute * 60
	
	//定义每天的秒数
	SecondsPerDay    = SecondsPerHour * 24
)

//将传入的“秒”解析为3种时间单位
func resolveTime(seconds int) (day int, hour int, minute int) {
	day = seconds / SecondsPerDay
	hour = seconds / SecondsPerHour
	minute = seconds / SecondsPerMinute
	return
}

func main() {
	//将返回值作为打印参数
	fmt.Println(resolveTime(1000))

	//只获取消息和分钟
	_, hour, minute := resolveTime(18000)
	fmt.Println(hour, minute)

	//只获取天
	day, _, _ := resolveTime(90000)
	fmt.Println(day)
}

运行结果如下:

0 0 16
5 300
1

示例:函数中的参数传递效果测试

代码如下:

package main

import (
	"fmt"
)

type Data struct {
	complax  []int
	instance InnerData
	ptr      *InnerData
}

type InnerData struct {
	a int
}

func passByValue(inFunc Data) Data {
	fmt.Printf("inFunc value: %+v\n", inFunc)
	fmt.Printf("inFunc ptr: %p\n", &inFunc)
	return inFunc
}

func main() {
	in := Data{
		complax: []int{1, 2, 3},
		instance: InnerData{
			5,
		},
		ptr: &InnerData{1},
	}
	fmt.Printf("in value: %+v\n", in)
	fmt.Printf("in ptr: %p\n", &in)
	out := passByValue(in)
	fmt.Printf("out value:%+v\n", out)
	fmt.Printf("out ptr: %p\n", &out)
}

运行结果如下:

in value: {complax:[1 2 3] instance:{a:5} ptr:0xc0000aa058}
in ptr: 0xc0000c2450
inFunc value: {complax:[1 2 3] instance:{a:5} ptr:0xc0000aa058}
inFunc ptr: 0xc0000c24e0
out value:{complax:[1 2 3] instance:{a:5} ptr:0xc0000aa058}
out ptr: 0xc0000c24b0

函数变量——把函数作为值保存到变量中

代码如下:

package main

import (
	"fmt"
)

func fire() {
	fmt.Println("fire")
}

func main() {
	var f func()
	f = fire
	f()
}

运行结果如下:

fire

示例:字符串的链式处理——操作与数据分离的设计技巧

代码如下:

package main

import (
	"fmt"
	"strings"
)
//字符串处理函数,传入字符串切片和处理链
func StringProccess(list []string, chain []func(string) string) {
	//遍历每一个字符串
	for index, str := range list {
		//第一个需要处理的字符串
		result := str
		//遍历每一个处理链
		for _, proc := range chain {
			//输入一个字符串进行处理,返回数据作为下一个处理链的输入
			result = proc(result)
		}
		//将结果放回切片
		list[index] = result
	}
}

//自定义的移除前缀的处理函数
func removePrefix(str string) string {
	return strings.TrimPrefix(str, "go")
}

func main() {
	//待处理的字符串列表
	list := []string{
		"go scanner",
		"go parser",
		"go compiler",
		"go printer",
		"go formater",
	}
	//处理函数链
	chain := []func(string) string{
		removePrefix,
		strings.TrimSpace,
		strings.ToUpper,
	}
	//处理字符串
	StringProccess(list, chain)
	//输出处理好的字符串
	for _, str := range list {
		fmt.Println(str)
	}
}

运行结果如下:

SCANNER
PARSER
COMPILER
PRINTER
FORMATER

匿名函数——没有函数名字的函数

1、定义一个匿名函数

匿名函数的定义格式如下:

func (参数列表) (返回参数列表) {

        函数体

}

2、匿名函数用作回调函数

代码如下:

package main

import (
	"fmt"
)

//遍历切片的每个元素,通过给定函数进行元素访问
func visit(list []int, f func(int)) {
	for _, v := range list {
		f(v)
	}
}

func main() {
	//使用匿名函数打印切片内容
	visit([]int{1, 2, 3, 4}, func(v int) {
		fmt.Println(v)
	})
}

运行结果如下:

1
2
3
4

3、使用匿名函数实现操作封装

代码如下:

package main

import (
	"flag"
	"fmt"
)

var skillParam = flag.String("skill", "", "skill to perform")

func main() {
	flag.Parse()
	var skill = map[string]func(){
		"fire": func() {
			fmt.Println("chicken fire")
		},
		"run": func() {
			fmt.Println("soldier run")
		},
		"fly": func() {
			fmt.Println("angel fly")
		},
	}
	if f, ok := skill[*skillParam]; ok {
		f()
	} else {
		fmt.Println("skill not found")
	}
}

运行结果如下:

PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go
skill not found
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go --skill=fire
chicken fire
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go --skill=run
soldier run
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go --skill=fly
angel fly

函数类型实现接口——把函数作为接口来调用

1、结体体实现接口

2、函数体实现接口

3、HTTP包中的例子

闭包(Closure)——引用了外部变量的匿名函数

函数+引用环境=闭包

代码如下:

package main

import (
	"fmt"
)

func main() {
	add := func(base int) func(int) int {
		return func(n int) int {
			return base + n
		}
	}
	add5 := add(5)
	fmt.Println(add5(10))
}

运行结果如下:

15

1、在闭包内部修改引用的变量

代码如下:

package main

func main() {
	//准备一个字符串
	str := "hello world"
	//创建一个匿名函数
	foo := func() {
		//匿名函数中访问str
		str = "hello dude"
	}
	//调用匿名函数
	foo()
}

代码输出:hello dude

2、示例:闭包的记忆效应

代码如下:

package main

import (
	"fmt"
)

//提供一个值,每次调用函数会指定对值进行累加
func Accumulate(value int) func() int {
	//返回一个闭包
	return func() int {
		//累加
		value++
		//返回一个累加值
		return value
	}
}
func main() {
	//创建一个累加器,初始值为1
	accumulator := Accumulate(1)
	//累加1并打印
	fmt.Println(accumulator())
	fmt.Println(accumulator())
	//打印累加器的函数地址
	fmt.Printf("%p\n", &accumulator)
	//创建一个累加器,初始值为1
	accumulator2 := Accumulate(10)
	//累加1并打印
	fmt.Println(accumulator2())
	//打印累加器的函数地址
	fmt.Printf("%p\n", &accumulator2)
}

运行结果如下:

2
3
0xc000006028
11
0xc000006038

3、示例:闭包实现生成器

代码如下:

package main

import (
	"fmt"
)

//创建一个玩家生成器,输入名称,输出生成器
func playerGen(name string) func() (string, int) {
	//血量一直为150
	hp := 150
	//返回创建的闭包
	return func() (string, int) {
		//将变量引用到闭包中
		return name, hp
	}
}
func main() {
	//创建一个玩家生成器
	generator := playerGen("high noon")
	//返回玩家的名字和血量
	name, hp := generator()
	//打印值
	fmt.Println(name, hp)
}

运行结果如下:

high noon 150

可变参数——参数数量不固定的函数形式

Go语言的可变参数格式如下:

func 函数名 (固定参数列表,v… T) (返回参数列表) {

函数体

}

可变参数一般被放置在函数列表的末尾,前面是固定参数列表,当没有固定参数时,所有变量就将是可变参数。

v为可变参数变量,类型为[]T,也就是拥有多个T元素的T类型切片,v和T之间由“…”即3个点组成。

T为可变参数的类型,当T为interface{}时,传入的可以是任意类型。

1、fmt包中的例子

2、遍历可变参数列表——获取每一个参数的值

代码如下:

package main

import (
	"bytes"
	"fmt"
)

//定义一个函数,参数数量为0~n,类型约束为字符串
func joinStrings(slist ...string) string {
	//定义一个字节缓冲,快速地连接字符串
	var b bytes.Buffer
	//遍历可变参数列表slist,类型为[]string
	for _, s := range slist {
		//将遍历出的字符串连续写入字节数组
		b.WriteString(s)
	}
	//将连续好的字节数组转换为字符串并输出
	return b.String()
}

func main() {
	//创建一个玩家生成器
	fmt.Println(joinStrings("pig", " and", " rat"))
	fmt.Println(joinStrings("hammer", " mom", " and", " hawk"))
}

运行结果如下:

pig and rat
hammer mom and hawk

3、获得可变参数类型——获得每一个参数的类型

代码如下:

package main

import (
	"bytes"
	"fmt"
)

func printTypeValue(slist ...interface{}) string {
	//字节缓冲作为快速字符串连接
	var b bytes.Buffer
	//遍历参数
	for _, s := range slist {
		//将interface{}类型格式化为字符串
		str := fmt.Sprintf("%v", s)
		//类型的字符串描述
		var typeString string
		//对s进行类型断言
		switch s.(type) {
		case bool: //当s为布尔类型时
			typeString = "bool"
		case string: //当s为字符串类型时
			typeString = "string"
		case int: //当s为整形类型时
			typeString = "int"
		}
		//写值字符串前缀
		b.WriteString("value:")
		//写入值
		b.WriteString(str)
		//写类型前缀
		b.WriteString(" type: ")
		//写类型字符串
		b.WriteString(typeString)
		//写入换行符
		b.WriteString("\n")
	}
	return b.String()
}

func main() {
	//将不同类型的变量通过printTypeValue()打印出来
	fmt.Println(printTypeValue(100, "str", true))
}

运行结果如下:

value:100 type: int
value:str type: string
value:true type: bool

4、在多个可变参数函数中传递参数

代码如下:

package main

import (
	"fmt"
)

//实际打印的函数
func rawPrint(rawList ...interface{}) {
	//遍历可变参数切片
	for _, a := range rawList {
		//打印参数
		fmt.Println(a)
	}
}

//打印函数封装
func print(slist ...interface{}) {
	//将slist可变参数切片完整传凝视给下一个函数
	rawPrint(slist...)
}

func main() {
	print(1, 2, 3)
}

运行结果如下:

1
2
3

延迟执行语句(defer)

一、多个延迟执行语句的处理顺序

代码如下:

package main

import (
	"fmt"
)

func main() {
	fmt.Println("defer begin")
	//将defer放入延迟调用栈
	defer fmt.Println(1)
	defer fmt.Println(2)
	//最后一个放入,位于栈顶,最先调用
	defer fmt.Println(3)
	fmt.Println("defer end")
}

代码输出如下:

defer begin
defer end
3
2
1

二、使用延迟执行语句在函数退出时释放资源

1、使用延迟并发解锁

2、使用延迟释放文件句柄

处理运行时发生的错误

一、net包中的例子

net.Dial()是Go语言系统包net即中的一个函数,一般用于创建一个Socket连接。

net.Dial拥有两个返回值,即Conn和error。这个函数阻塞的,因此在Socket操作后,会返回Conn连接对象和error;如果发生错误,error会告知错误的类型,Conn会返回空。

二、错误接口的定义格式

type error interface{

        Error() string

}

三、自定义一个错误

代码如下:

package main

import (
	"errors"
	"fmt"
)

//定义除数为0的错误
var errDivisionByZero = errors.New("division by zoro")

func div(dividend, divisor int) (int, error) {
	//判断除数为0的情况并返回
	if divisor == 0 {
		return 0, errDivisionByZero
	}
	//正常计算,返回空错误
	return dividend / divisor, nil
}

func main() {
	fmt.Println(div(1, 0))
}

运行结果如下:

0 division by zoro

四、示例:在解析中使用自定义错误

代码如下:

package main

import (
	"fmt"
)

//声明一个解析错误
type ParseError struct {
	Filename string //文件名
	Line     int    //行号
}

//实现error接口,返回错误描述
func (e *ParseError) Error() string {
	return fmt.Sprintf("%s:%d", e.Filename, e.Line)
}

//创建一些解析错误
func newParseError(filename string, line int) error {
	return &ParseError{filename, line}
}

func main() {
	var e error
	//创建一个错误实例,包含文件名和行号
	e = newParseError("main.go", 1)
	//通过error接口查看错误描述
	fmt.Println(e.Error())
	//根据错误接口的具体类型,获取详细的错误信息
	switch detail := e.(type) {
	case *ParseError:		//这是一个解析错误
		fmt.Printf("Filename:%s Line:%d\n", detail.Filename, detail.Line)
	default:				//其他类型的错误
		fmt.Println("other error")
	}
}

运行结果如下:

main.go:1
Filename:main.go Line:1

宕机(panic)——程序终止运行

一、手动触发宕机

代码如下 :

package main

func main() {
	panic("crash")
}

运行结果如下:

panic: crash

goroutine 1 [running]:
main.main()
        C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:4 +0x27
exit status 2

二、在运行依赖的必备资源缺失时主动触发宕机。

func Compile(expr string) (*Regexp, error)

func MustCompile(str string) *Regexp

三、在宕机时触发延迟执行语句

代码如下:

package main

import (
	"fmt"
)

func main() {
	defer fmt.Println("宕机后要做的事情1")
	defer fmt.Println("宕机后要做的事情2")
	panic("宕机")
}

运行结果如下:

宕机后要做的事情2
宕机后要做的事情1
panic: 宕机

goroutine 1 [running]:
main.main()
        C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:10 +0xac
exit status 2

宕机恢复(recover)——防止程序崩溃

一、让程序在崩溃时继续执行

代码如下:

package main

import (
	"fmt"
	"runtime"
)

//崩溃时需要传递的上下文信息
type panicContext struct {
	function string //所在函数
}

//保护方式允许一个函数
func ProtectRun(entry func()) {
	//延迟处理的函数
	defer func() {
		//发生宕机时,获取panic传递的上下文并打印
		err := recover()
		switch err.(type) {
		case runtime.Error: //运行时错误
			fmt.Println("runtime error:", err)
		default:
			fmt.Println("error:", err)
		}
	}()
	entry()
}

func main() {
	fmt.Println("运行前")
	//允许一段手动触发的错误
	ProtectRun(func() {
		fmt.Println("手动宕机前")
		//使用panic传递上下文
		panic(&panicContext{
			"手动触发panic",
		})
		fmt.Println("手动宕机后")
	})
	//故意造成空指针访问错误
	ProtectRun(func() {
		fmt.Println("赋值宕机前")
		var a *int
		*a = 1
		fmt.Println("赋值宕机后")
	})
	fmt.Println("运行后")
}

运行结果如下:

运行前
手动宕机前
error: &{手动触发panic}
赋值宕机前
runtime error: runtime error: invalid memory address or nil pointer dereference
运行后

二、panic和recover的关系

有panic没recover,程序宕机。

有panic也有recover捕获,程序不会宕机。执行完对应的defer后,从宕机点退出当前函数后继续执行。

派错和恢复:

Go语言提供丙个内置函数来处理运行时的程序错误:panic结束函数的执行并报告一个错误信息;recover恢复被panic的函数。

代码如下:

package main

import (
	"log"
)

func protect(g func()) {
	defer func() {
		log.Println("done")
		if x := recover(); x != nil {
			log.Printf("run time panic: %v", x)
		}
	}()
	log.Println("start")
	g()
}

func main() {
	var s []byte
	protect(func() { s[0] = 0 })
	protect(func() { panic(42) })
	s[0] = 42
}

运行结果如下:

2022/03/24 16:03:44 start
2022/03/24 16:03:44 done
2022/03/24 16:03:44 run time panic: runtime error: index out of range [0] with length 0
2022/03/24 16:03:44 start
2022/03/24 16:03:44 done
2022/03/24 16:03:44 run time panic: 42
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
main.main()
        C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:22 +0x5b
exit status 2

方法:

代码如下:

package main

import (
	"fmt"
)

type Point struct {
	x, y float64
}
type Rect struct {
	min, max Point
}

func (r *Rect) Area() float64 {
	w := r.max.x - r.min.x
	h := r.max.y - r.min.y
	return w * h
}

func main() {
	var r Rect
	r.max = Point{2, 2}
	fmt.Println(r.Area())
}

运行结果如下:

4

代码如下:

package main

import (
	"fmt"
)

type Point struct {
	x, y float64
}
type Rect struct {
	min, max Point
}

func (r *Rect) Area() float64 {
	w := r.max.x - r.min.x
	h := r.max.y - r.min.y
	return w * h
}

func (r Point) Area() float64 {
	return 0
}

func main() {
	var r Rect
	r.max = Point{2, 2}
	fmt.Println(r.Area(), (&r).Area(), (*Rect).Area(&r))
	p := &r.min
	fmt.Println(p.Area(), (*p).Area(), Point.Area(r.min))
}

运行结果如下:

4 4 4
0 0 0

显式与隐式代码块

代码如下:

package main

import (
	"fmt"
)

var (
	Ga int = 99
)

const (
	v int = 199
)

func GetGa() func() int {
	if Ga := 55; Ga < 60 {
		fmt.Println("GetGa if 中:", Ga)
	}
	for Ga := 2; ; {
		fmt.Println("GetGa循环中:", Ga)
		break
	}
	fmt.Println("GetGa函数中:", Ga)
	return func() int {
		Ga += 1
		return Ga
	}
}

func main() {
	Ga := "string"
	fmt.Println("main函数中:", Ga)
	b := GetGa()
	fmt.Println("main函数中:", b(), b(), b(), b())
	v := 1
	{
		v := 2
		fmt.Println(v)
		{
			v := 3
			fmt.Println(v)
		}
	}
	fmt.Println(v)
}

运行结果如下:

main函数中: string
GetGa if 中: 55
GetGa循环中: 2
GetGa函数中: 99
main函数中: 100 101 102 103
2
3
1

代码如下:

package main

import (
	"fmt"
	"time"
)

type funcType func(time.Time) // 定义函数类型funcType

func main() {
	f := func(t time.Time) time.Time { return t } // 直接赋值给变量
	fmt.Println(f(time.Now()))

	var timer funcType = CurrentTime // 定义函数类型funcType变量timer
	timer(time.Now())

	funcType(CurrentTime)(time.Now()) // 先把CurrentTime函数转为funcType类型,然后传入参数调用
	// 这种处理方式在Go 中比较常见
}

func CurrentTime(start time.Time) {
	fmt.Println(start)
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
2022-05-30 16:33:11.1125094 +0800 CST m=+0.004932401
2022-05-30 16:33:11.1334169 +0800 CST m=+0.025839901
2022-05-30 16:33:11.1334169 +0800 CST m=+0.025839901

[Done] exited with code=0 in 11.801 seconds

代码如下:

package main

import (
	"fmt"
)

// 变参函数,参数不定长
func list(nums ...int) {
	fmt.Println(nums)
}

func main() {
	// 常规调用,参数可以多个
	list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

	// 在参数同类型时,可以组成slice使用 parms... 进行参数传递
	numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	list(numbers...) // slice时使用
}

运行结果如下:

[Running] go run "c:\Program Files\Go\src\main.go"
[1 2 3 4 5 6 7 8 9 10]
[1 2 3 4 5 6 7 8 9 10]

[Done] exited with code=0 in 3.617 seconds

递归与回调:

代码如下:

package main

import "fmt"

// Factorial函数递归调用
func Factorial(n uint64) (result uint64) {
	if n > 0 {
		result = n * Factorial(n-1)
		return result
	}
	return 1
}

// Fac2函数循环计算
func Fac2(n uint64) (result uint64) {
	result = 1
	var un uint64 = 1
	for i := un; i <= n; i++ {
		result *= i
	}
	return
}

func main() {
	var i uint64 = 7
	fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(i))
	fmt.Printf("%d 的阶乘是 %d\n", i, Fac2(i))

}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
7 的阶乘是 5040
7 的阶乘是 5040

[Done] exited with code=0 in 2.442 seconds

代码如下:

package main

import (
	"fmt"
)

func main() {
	callback(1, Add)
}

func Add(a, b int) {
	fmt.Printf("%d 与 %d 相加的和是: %d\n", a, b, a+b)
}

func callback(y int, f func(int, int)) {
	f(y, 2) // 回调函数f
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
1 与 2 相加的和是: 3

[Done] exited with code=0 in 15.635 seconds

匿名函数:

代码如下:

package main

import (
	"fmt"
)

func main() {
	fn := func() {
		fmt.Println("hello")
	}
	fn()

	fmt.Println("匿名函数加法求和:", func(x, y int) int { return x + y }(3, 4))

	func() {
		sum := 0
		for i := 1; i <= 1e6; i++ {
			sum += i
		}
		fmt.Println("匿名函数加法循环求和:", sum)
	}()
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
hello
匿名函数加法求和: 7
匿名函数加法循环求和: 500000500000

[Done] exited with code=0 in 14.025 seconds

代码如下:

package main

import "fmt"

var G int = 7

func main() {
	// 影响全局变量G,代码块状态持续
	y := func() int {
		fmt.Printf("G: %d, G的地址:%p\n", G, &G)
		G += 1
		return G
	}
	fmt.Println(y(), y)
	fmt.Println(y(), y)
	fmt.Println(y(), y) //y的地址

	// 影响全局变量G,注意z的匿名函数是直接执行,所以结果不变
	z := func() int {
		G += 1
		return G
	}()
	fmt.Println(z, &z)
	fmt.Println(z, &z)
	fmt.Println(z, &z)

	// 影响外层(自由)变量i,代码块状态持续
	var f = N()
	fmt.Println(f(1), &f)
	fmt.Println(f(1), &f)
	fmt.Println(f(1), &f)

	var f1 = N()
	fmt.Println(f1(1), &f1)

}

func N() func(int) int {
	var i int
	return func(d int) int {
		fmt.Printf("i: %d, i的地址:%p\n", i, &i)
		i += d
		return i
	}
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\tempCodeRunnerFile.go"
G: 7, G的地址:0x9fd258
8 0x95e440
G: 8, G的地址:0x9fd258
9 0x95e440
G: 9, G的地址:0x9fd258
10 0x95e440
11 0xc0000aa080
11 0xc0000aa080
11 0xc0000aa080
i: 0, i的地址:0xc0000aa088
1 0xc0000ce020
i: 1, i的地址:0xc0000aa088
2 0xc0000ce020
i: 2, i的地址:0xc0000aa088
3 0xc0000ce020
i: 0, i的地址:0xc0000aa090
1 0xc0000ce028

[Done] exited with code=0 in 3.033 seconds

变参函数:

代码如下:

package main

import "fmt"

func Greeting(who ...string) {
	for k, v := range who {

		fmt.Println(k, v)
	}
}

func main() {
	s := []string{"James", "Jasmine"}
	Greeting(s...) // 注意这里切片s... ,把切片打散传入,与s具有相同底层数组的值。
}

运行结果如下:

[Running] go run "c:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\深入学习Go语言\63072_go42\63072_go42\chapter-8\8.1\7\tempCodeRunnerFile.go"
0 James
1 Jasmine

[Done] exited with code=0 in 11.987 seconds

电磁场仿真软件:Sonnet_(1).Sonnet软件概述 根据特定需求自定义仿真流程,如多频率点仿真、多边界条件仿真等。 阅读详情

相关推荐

绕开华为通道,获取解锁码解锁BootLoader

刷机有风险,操作需谨慎,如果因为各种因素导致手机变砖无法开机,本教程概不负责,望悉知 前言 这篇文章的大多内容是根据我自己找的一篇文章《绕开华为通道,获取解锁码解锁BootLoader》来编写的,里面的大部分内容是文章的原内容。下面的都是我参考文章中做了一些小部分的修改,增加了我华为P8手机的一些操作,下面开始讲述我的解锁过程。 因为华为官方在2018年的七八月份吧,关闭了解锁码的申请通道,这...

Martin.Mu `s Special Column 5万+

【Go】Go 语言函数

文章目录一、函数二、函数的声明三、函数的调用四、函数参数1. 值传递2. 引用传递五、函数用法1. 函数作为实参2. 闭包3. 方法六、内置函数参考链接 一、函数 函数是基本的代码块,用于执行一个任务。 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。 Go 语言最少有个 main() 函数。 二、函数的声明 函数声明告诉了编译器函数的名称,返回类型,和参数。 函数定义格式如下: func name( [parameter list] ) [return_types] { 函数体

weixin_44211968的博客 4684

中文文本纠错实战:pycorrector与kenlm的安装与高效使用指南

本文提供了一份详细的中文文本纠错实战指南,重点介绍了pycorrector与kenlm的安装与高效使用方法。内容涵盖从编译环境准备、依赖安装到核心参数调优、批量处理及领域自适应等全流程,旨在帮助开发者快速部署并优化纠错系统,提升中文文本处理的质量与效率。

weixin_29055699的博客 411

【Go语言】Go语言中的函数

Go语言默认使用按值传参来传递参数,也就是传递参数值的一个副本,函数收到传递进来的参数后,会将参数值拷贝给声明该参数的变量(也叫做形式参数,简称形参),如果在函数体中有对参数值做修改,实际上修改的是形参值,这不会影响到实际传递进来的参数值(也叫实际参数,简称实参)。如果需要实现在函数中修改形参值的同时改变实参,需要引用传参来实现,此时传递给函数的参数是一个指针,而指针代表的是实参的内存地址,修改指针引用的值即修改变量内存地址中存储的值,因此实参的值也会被修改。指引用了外部函数作用域中的变量的函数。

Python、Golang、大数据 2790

【Zotero】《纯操作讲解,GPT配置,Zotero标注可视化》- 知识点目录

Temperature分布在。之间,越低输出越稳定;

墨门 3396

2025年从零开始:构建你的首个ComfyUI工作流-ComfyUI入门教程

然而,由于它拥有众多的插件节点,以及较为复杂的操作流程,学习起来相对困难。以前面搭建的文生图工作流为例,首先点击功能区的【保存】,然后你的浏览器会出来一个弹窗,你可以进行文件命名,点击确定后浏览器会下载该文件,也就是带“json”后缀的文件,这样我们的工作流就打包成一份文件了。思考一下前面说的,节点是不是需要下载安装才能使用,而我们复用别人的工作流,他用的节点你不一定下载了,因为目前有600多个节点,你不可能全部下载了吧,所以我们日后使用别人的工作流,你会经常出现这样的问题。

weixin_59486588的博客 1455

go 函数 详解

go 函数 详解函数的定义和使用不定参函数函数嵌套使用函数返回值函数类型函数的作用域局部变量全局变量 函数的定义和使用 (1)语法: func 函数名(形参列表)(返回值类型列表){    //代码体(程序体)    执行语句…    return + 返回值列表 } 函数定义:只能定义一次,名字是唯一的。 package main import "fmt" //函数定义 只能定义一次 名字是唯一的 func

weixin_59633478的博客 3815

ZYNQ Linux环境下PS端I2C驱动OV5640摄像头全流程解析

本文详细解析了在ZYNQ Linux环境下,通过PS端I2C驱动OV5640摄像头的完整流程。内容涵盖从Vivado硬件配置、PetaLinux系统构建、设备树节点添加,到用户空间I2C编程与寄存器配置实战,并提供了关键的调试技巧与常见问题排查方法,帮助开发者快速实现嵌入式视觉应用的传感器配置。

vulkan6gpu的博客 853

Go语言函数

Go语言函数

YIYIYI 1206

点云焊缝提取

本文介绍了一个基于PCL库的点云处理流程,包含三个核心模块:MLS平滑处理通过多项式拟合修正点云位置;差异提取通过双向匹配定位源/目标点云的非重叠区域;统计过滤剔除离群噪声点。该流程采用"平滑-筛选-净化"的通用思路,将复杂算法封装为可配置接口,实现了工业级点云预处理。文章重点分析了各模块的原理、PCL接口调用及参数设计逻辑,同时指出参数调优、算法扩展等深入探索方向,展现了PCL在点云处理中的模块化优势与实用价值。

weixin_45196569的博客 250

OpenCV-Python实战(10)——详解 OpenCV 轮廓检测

在计算机视觉领域,轮廓通常指图像中对象边界的一系列点。因此,轮廓通常描述了对象边界的关键信息,包含了有关对象形状的主要信息,该信息可用于形状分析与对象检测和识别。在本文中,将首次通过简单示例了解轮廓的基本概念,然后通过实际示例来了解如何检测和压缩轮廓,最后利用介绍如何利用图像矩描述检测到的轮廓属性。

盼小辉丶的博客 3万+

Go 语言函数

/ 定义函数类型// 使用函数类型// 实现函数类型// 使用函数类型。

LWCT 820

使用R语言实战:构建Logistic回归模型

Logistic回归是一种基于概率的分类算法,它用于预测离散的结果变量(也称为响应变量或因变量)。与线性回归不同,Logistic回归的输出是一个概率值,通常在0和1之间。这使得它非常适合处理二分类问题。市场营销:预测客户是否会购买某个产品。医学研究:预测疾病的发生与否。信用风险评估:预测个人申请贷款的违约风险。社会科学:预测个人对某个政策的态度。

2301_79331230的博客 1140

go语言func后面括号_Golang语言基础教程:函数初识

1.1 什么是函数函数是执行特定任务的代码块。1.2 函数的声明go语言至少有一个main函数语法格式:func funcName(parametername type1, parametername type2) (output1 type1, output2 type2) { //这里是处理逻辑代码 //返回多个值 return value1, value2 } func:函数由 func 开...

weixin_28953819的博客 3341

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

13 go语言(golang) - 函数

一个简单的函数定义包括关键字func、函数名、参数列表、返回值列表(可选)以及函数体。func 函数名(参数列表) 返回值类型 {函数体func:用于声明一个新函数。函数名:这是函数的名称。参数列表:表示该函数接的参数。返回值类型:表示该函数返回的结果类型,没有返回时可以省略。函数体:包含了实际执行操作的代码块。

瑞瑞的博客 917

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【Golang 基础系列十四】Go 语言函数

概述 函数是基本的代码块,用于执行一个任务 语法 函数定义 func 函数名称( 参数列表] ) (返回值列表]){ 执行语句 } 一.函数参数 无参数无返回 func add() 有参数有返回 func add(a, b int) int 函数值传递 func swap(x,y int) int { var temp int temp = x x = y y ...

郭枫的博客 647

Go语言自学系列 | golang 函数

视频来源:B站《golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]》 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! 附上汇总贴:Go语言自学系列 | 汇总_COCOgsta的博客-优快云博客 golang函数简介 函数的go语言中的一级公民,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数的名称、参数列表和返回值类型,这些构成了函数的签名(signature)。 go语言中函数特性 go语言中有3种函数:普

团爸讲算法 773

【Golang】Go语言函数

Go语言函数特点包括:无需声明原型、支持不定变参、多返回值、匿名函数和闭包,函数可作为类型赋值给变量,但不支持嵌套、重载和默认参数。文章介绍了基本函数定义格式、匿名函数、自执行函数(只执行一次)、闭包函数(返回函数的函数)以及延迟调用(defer)机制。通过示例代码展示了各种函数的使用方式,包括参数传递、返回值处理、函数赋值等特性。

weixin_73059729的博客 459

Go语言自学系列 | golang高阶函数

视频来源:B站《golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]》 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! 附上汇总贴:Go语言自学系列 | 汇总_COCOgsta的博客-优快云博客 go语言的函数,可以作为函数的参数,传递给另外一个函数,作为另外一个函数的返回值返回。 go语言函数作为参数 package main import "fmt" func sayHello(name string) {

团爸讲算法 920

Go语言自学系列 | golang函数的返回值

视频来源:B站《golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]》 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! 附上汇总贴:Go语言自学系列 | 汇总_COCOgsta的博客-优快云博客 函数可以有0或多个返回值,返回值需要指定数据类型,返回值通过return关键字来指定。 return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。 return关键字中指定了参数时,返

团爸讲算法 8146

【go语言】函数

在 go 语言中,函数是代码块的集合,用于执行特定任务或者计算。函数接受输入(成为参数),执行操作并返回输出(称为返回值)。go 语言中的函数定义非常简单且灵活。在 go 语言中,函数通过 func 关键字定义。func:用于声明函数。:函数的名字,通常首字母大写表示公开(exported)函数,首字母小写表示私有(unexported)函数。:参数列表(可选),参数使用name type的格式。多个参数之间用逗号分隔。returnType:返回值类型(可选)。如果函数没有返回值,则省略。

加油,考上985的研究生 1541

Golang基础语法(go语言函数、闭包)

/ 函数体func:函数关键字,任何一个函数都有func关键字开始声明。function_name:函数名称,参数列表和返回值类型构成了函数签名。parameter list:参数列表,参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。函数体:函数定义的代码集合。

Atticus的博客 797

C语言竟可以调用Go语言函数,这是如何实现的?

大家好,我是飞哥!今天和大家聊一个问题,一门语言是否可以在同一个进程内调用另外一门语言实现的函数?例如 C 语言是否可以调用 Golang 实现的函数?注意我说的是同进程内调用,跨进程的 IPC、PRC 之类的技术不算。直接抛出这个问题的答案,同进程跨语言调用是可行的。在各种语言设计时,为了复用其它语言生态中积累下来的大量的代码资产,都会实现跨语言调用的机制。例如在 Golang 中,实现了 cg...

zhangyanfei01的专栏 973

Go语言学习笔记—golang函数

golang 函数

qq_39280718的博客 592

【Golang 基础】 Go 语言 函数式编程

Go 语言函数式编程   在 Go 语言中函数是一等公民,它作为一个变量、类型、参数、返回值,甚至可以去实现一个接口,但是 Go 语言中函数不支持重载、嵌套和默认参数。 通过使用 func关键字来定义函数 package main func main(){ } 函数支持的特性 作为变量; func test(){ // 函数体 } funcTest := test fm...

hvkCoder的博客 531

Go语言自学系列 | golang函数的参数

视频来源:B站《golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]》 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! 附上汇总贴:Go语言自学系列 | 汇总_COCOgsta的博客-优快云博客 go语言函数可以有0或多个参数,参数需要指定数据类型。 声明函数时的参数列表叫做形参,调用时传递的参数叫做实参。 go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问、修改的也是这个副本。 go语言可以

团爸讲算法 2392

golang延时_关于go 语言中的延迟执行函数

许多内置的带有返回值的函数无法进行延迟调用在go语言中,调用自定义函数的结果值可以全部不存在(丢弃)。但是,对于具有非空白返回结果列表的内置函数,他们的调用的结果不可以抛弃,copy和recover例外。 换句话说,延迟执行函数的结果必须被抛弃,所以许多内置函数无法被延迟。幸运的是,在实践中,很有偶需要延迟执行内置函数的地方。据我所知,只有append函数可能需要被延迟执行。这种情况下,我们可以把...

weixin_33205735的博客 4395
上一篇: Go语言的转换不同的数据类型
下一篇: 在Visual Studio出现一个编译错误,返回值被忽略: “scanf”(代码:C6031)
DXB2021
博客等级 码龄5年 307粉丝 289原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值