Task 07 函数

本文聚焦Go语言函数,介绍了函数的基本概念,包括函数声明与定义格式。详细阐述了值传递与引用传递的区别,还提及变长函数、函数返回多个值、命名返回值等特性。此外,对匿名函数、闭包的概念及用法进行讲解,并给出相关实例。

函数

函数是基本的代码块,用于执行一个任务。可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。函数声明告诉了编译器函数的名称,返回类型,和参数。

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

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

  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • parameter
    list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下
    return_types 不是必须的。
  • 函数体:函数定义的代码集合。

实例:
以下实例为 max() 函数的代码,该函数传入两个整型参数 num1 和 num2,并返回这两个参数的最大值:

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 声明局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result
}

值传递与引用传递
因为在go语言中存在值类型与引用类型,所以在函数参数进行传递时也要注意这个问题。

  • 值传递是指在函数调用过程中将实参拷贝一份到函数中,这样在函数中如果对参数进行修改,将不会影响到实参。
  • 引用传递是指在函数调用过程中将实参的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实参。
    如果想要函数可以直接修改参数的值,那么我们可以用指针传递,将变量的地址作为参数传递到函数中。
    实例:
func paramFunc(a int, b *int, c []int) {
	a = 100
	*b = 100
	c[1] = 100

	fmt.Println("paramFunc:")
	fmt.Println(a)
	fmt.Println(*b)
	fmt.Println(c)
}

func main() {
	a := 1
	b := 1
	c := []int{1, 2, 3}
	paramFunc(a, &b, c)

	fmt.Println("main:")
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
}

输出如下:

paramFunc:
100
100
[1 100 3]
main:
1
100
[1 100 3]

变长函数
实例:

func main() {
	slice := []int{7, 9, 3, 5, 1}
	x := min(slice...)
	fmt.Printf("The minimum is: %d", x)
}

func min(s ...int) int {
	if len(s) == 0 {
		return 0
	}
	min := s[0]
	for _, v := range s {
		if v < min {
			min = v
		}
	}
	return min
}

上面这段代码直接将切片作为参数也能实现同样的效果,但是变长参数更多的是为了参数不确定的情况,例如fmt包中的Printf函数设计如下:

func Printf(format string, a …interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a…)
}

函数返回多个值
实例:

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Hello", "Wrold")
   fmt.Println(a, b)
}

输出如下:

Hello World

命名返回值
实例:

func div(a, b float64) (result float64, err error) {
	if b == 0 {
		return 0, errors.New("被除数不能等于0")
	}
	result = a / b
	return
}

注:即使只有一个命名返回值,也需要使用()括起来。

匿名函数
匿名函数如其名字一样,是一个没有名字的函数,除了没有名字外其他地方与正常函数相同。匿名函数可以直接调用,保存到变量,作为参数或者返回值。
实例:

func main() {
	f := func() string {
		return "hello world"
	}
	fmt.Println(f())
}

闭包
闭包可以解释为一个函数与这个函数外部变量的一个封装。粗略的可以理解为一个类,类里面有变量和方法,其中闭包所包含的外部变量对应着类中的静态变量。
实例:

func add() func(int) int {
	n := 10
	str := "string"
	return func(x int) int {
		n = n + x
		str += strconv.Itoa(x)
		fmt.Print(str, " ")
		return n
	}
}

func main() {
	f := add()
	fmt.Println(f(1))
	fmt.Println(f(2))
	fmt.Println(f(3))

	f = add()
	fmt.Println(f(1))
	fmt.Println(f(2))
	fmt.Println(f(3))
}

输出如下:

string1 11
string12 13
string123 16
string1 11
string12 13
string123 16

用闭包实现斐波那契数列:

package main

import "fmt"

func fibonacci() func() int {
	back1, back2 := 0, 1

	return func() int {
		temp := back1
		back1, back2 = back2, (back1 + back2)
		return temp
	}
}
func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

输出如下;

0
1
1
2
3
5
8
13
21
34

参考:
datawhalechina
菜鸟教程

在AUTOSAR环境中,任务延迟的实现通常依赖于操作系统(OS)提供的延时机制。AUTOSAR OS基于OSEK OS标准进行扩展,支持基于时间事件的任务调度与控制。任务延迟函数通常通过调用`ActivateTask()`与`WaitEvent()`等API结合系统时钟实现。 任务延迟的实现方式可以分为以下几种: 1. **基于系统时钟的等待** AUTOSAR OS提供了系统时钟服务,通过调用`GetCounterValue()`和`WaitEvent()`等函数实现基于时间的等待。例如,在任务中等待一定的时间后继续执行,可以通过等待特定的事件并结合系统计数器来实现。 2. **使用操作系统提供的延时服务** AUTOSAR OS支持`Schedule()`和`WaitEvent()`等函数,允许任务进入等待状态,直到某个事件发生或超时。以下是一个基于事件的延迟实现示例: ```c void DelayTask(uint32 delayTicks) { /* 设置延迟时间 */ SetRelAlarm(DelayAlarm, delayTicks, 0); /* 等待事件 */ WaitEvent(DelayEvent); /* 清除事件 */ ClearEvent(DelayEvent); } ``` 在该示例中,`SetRelAlarm()`用于设置一个相对时间的警报,当警报触发时会激活任务并触发`DelayEvent`,任务通过`WaitEvent()`等待该事件[^1]。 3. **基于任务激活的延迟** 另一种方法是通过`ActivateTask()`与`WaitEvent()`结合使用,使任务在被重新激活之前进入等待状态。这种方式适用于周期性任务或需要在特定时间点执行的任务。 4. **使用定时器回调函数** AUTOSAR OS支持通过定时器回调函数来实现延迟执行。开发者可以配置一个定时器,并在定时器到期时触发任务的执行。 在实际应用中,使用延迟函数时需要注意以下几点: - 延迟时间应以系统时钟节拍(tick)为单位进行配置,确保精度与系统调度的一致性。 - 在任务中使用延迟函数时,应避免阻塞其他高优先级任务的执行,确保系统的实时性。 - 延迟函数的实现应遵循AUTOSAR OS的规范,确保与系统其他模块的兼容性。 ### 示例代码 以下是一个简单的任务延迟函数的实现: ```c TASK(TaskWithDelay) { /* 执行任务初始化操作 */ ... /* 等待100个系统时钟节拍 */ DelayTask(100); /* 继续执行任务 */ ... TerminateTask(); } ``` ### 相关问题 1. AUTOSAR中如何配置系统时钟以支持任务延迟? 2. 如何在AUTOSAR中实现周期性任务? 3. 使用延迟函数时如何避免任务调度冲突? 4. AUTOSAR OS中有哪些与时间管理相关的API? 5. 如何确保延迟函数在多任务环境下的稳定性?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值