11.2 定义函数

在最简单的形式中,名为 name 的函数的定义如下所示:

function name
  body
endfunction

有效的函数名与有效的变量名规则相同:由字母、数字和下划线组成,且不能以数字开头。函数与变量共享同一个命名空间。

函数体 body 由 Octave 语句组成。它是定义中最重要的部分,因为它说明了函数实际上应该什么。

例如,下面这个函数在执行时会触发终端响铃(假设终端支持该功能):

function wakeup
  printf ("\a");
endfunction

这里的 printf 语句(请参阅 输入和输出)告诉 Octave 打印字符串 "\a"。特殊字符 \a 代表警报字符(ASCII 7)。另请参阅 字符串

一旦定义了这个函数,您就可以通过输入函数名称来让 Octave 执行它。

通常情况下,您会希望向定义的函数传递一些信息。在 Octave 中将参数传递给函数的语法如下:

function name (arg-list)
  body
endfunction

其中 arg-list 是函数参数的逗号分隔列表。当函数被调用时,参数名称用于保存调用时提供的参数值。参数列表可以为空,此时该形式与上面显示的形式等效。

要在响铃的同时打印消息,您可以修改 wakeup 函数,使其如下所示:

function wakeup (message)
  printf ("\a%s\n", message);
endfunction

使用如下语句调用此函数

wakeup ("Rise and shine!");

将导致 Octave 在终端响铃并打印消息 Rise and shine!,后面跟一个换行符(printf 语句第一个参数中的 \n)。

在大多数情况下,您还希望从定义的函数中获取一些返回值。以下是编写返回单个值的函数的语法:

function ret-var = name (arg-list)
  body
endfunction

符号 ret-var 是用于保存函数返回值的变量名称。该变量必须在函数体结束之前被赋值,函数才能正常返回值。

函数体中使用的变量是函数的局部变量。arg-listret-var 中命名的变量也是函数的局部变量。请参阅 全局变量,了解如何在函数内部访问全局变量。

例如,下面是一个计算向量元素平均值的函数:

function retval = avg (v)
  retval = sum (v) / length (v);
endfunction

如果我们把 avg 写成下面这样:

function retval = avg (v)
  if (isvector (v))
    retval = sum (v) / length (v);
  endif
endfunction

然后用矩阵而不是向量作为参数调用该函数,Octave 会打印如下错误消息:

error: value on right hand side of assignment is undefined

这是因为函数体中的 if 语句从未被执行,retval 也从未被定义。为了防止出现此类难以排查的错误,最好始终确保返回变量都被赋予了值,并在遇到问题时生成有意义的错误消息。例如,avg 可以改写为:

function retval = avg (v)
  retval = 0;
  if (isvector (v))
    retval = sum (v) / length (v);
  else
    error ("avg: expecting vector argument");
  endif
endfunction

这个函数仍然存在一个问题:如果在没有参数的情况下调用它会怎样?如果没有额外的错误检查,Octave 可能会打印一条错误消息,而这条消息并不能真正帮助您追踪错误的来源。为了让您能够捕获此类错误,Octave 为每个函数提供了一个名为 nargin 的自动变量。每次调用函数时,nargin 都会自动初始化为实际传递给函数的参数数量。例如,我们可以将 avg 函数重写为:

function retval = avg (v)
  retval = 0;
  if (nargin != 1)
    usage ("avg (vector)");
  endif
  if (isvector (v))
    retval = sum (v) / length (v);
  else
    error ("avg: expecting vector argument");
  endif
endfunction

如果用比预期更多的参数调用以 .m 文件代码编写的函数,Octave 会自动报告错误。但如果函数的参数过少,Octave 不会自动报告错误,因为函数通常可能有默认参数;不过,任何使用未赋值变量的尝试都会导致错误。函数可以检查调用时传入的参数,以避免此类问题,并提供更多针对具体上下文的错误消息。

 
n = nargin ()
n = nargin (fcn)

返回函数的输入参数数量。

如果在函数内部调用,则返回传递给该函数的参数数量。如果在顶层调用,则返回传递给 Octave 的命令行参数数量。

如果使用可选参数 fcn(函数名或函数句柄)调用,则返回该函数可接受的声明参数数量。

如果 fcn 的最后一个参数是 varargin,则返回值为负数。例如,集合运算的 union 函数声明为:

function [y, ia, ib] = union (a, b, varargin)

and

nargin ("union")
⇒   -3

编程说明:nargin 不适用于已编译的函数(.oct 文件),例如内置函数或动态加载的函数。

另请参阅: nargoutnarginchkvarargininputname

 
namestr = inputname (n)
namestr = inputname (n, ids_only)

返回传递给调用函数的第 n 个参数的名称。

如果该参数不是简单的变量名,则返回空字符串。例如,返回 "" 的情况包括:数字(5.1)、表达式(y/2),以及元胞或结构体索引(c{1}s.field)。

inputname 仅在函数内部有用。在命令行或脚本中使用时,它总是返回空字符串。

默认情况下,如果第 n 个参数不是有效的变量名,则返回空字符串。如果可选参数 ids_only 为 false,则返回该参数的文本,即使它不是有效的变量名。这是 Octave 的一个扩展功能,允许程序员在输入为复杂表达式时,也能精确查看函数是如何被调用的。

另请参阅: narginnarginchk

 
val = silent_functions ()
old_val = silent_functions (new_val)
old_val = silent_functions (new_val, "local")

查询或设置控制是否抑制函数内部输出的内部变量。

如果禁用此选项,Octave 将显示函数体中未以分号结尾的表达式求值所产生的结果。

当在函数内部使用 "local" 选项调用该函数时,该变量会在函数及其调用的任何子程序内部被局部更改。退出函数时将恢复原始变量值。


版权所有 © 2024-2026 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-4