HOWTO · MATLAB
从 Matlab 函数返回多个值
我们可以使用 MATLAB 中的方括号从函数返回多个值。
本页内容
MATLAB 函数可以在一次调用中返回多个彼此独立的输出。函数会在签名中声明输出变量,在函数体中为每个变量赋值,调用方则按相同顺序接收这些值。如果这些值共同构成一条逻辑记录,可以改为返回结构体或元胞数组;此时函数返回的是一个输出,其中包含多个字段或元素。
MATLAB 函数如何返回多个输出
函数定义中的方括号按顺序列出彼此独立的输出。例如,[sumValue, diffValue] 声明了两个输出。它们不会被打包成一种特殊的“多返回值”对象:每个输出都是一个普通值,会赋给调用方对应的变量。如果调用方请求某个输出,函数必须在返回前为其赋值。
选择调用方式时,这一区别很重要。调用方可以只请求第一个输出,也可以请求多个输出。不能通过留空来跳过某个位置;对于不需要的输出,应在相应位置使用 ~。结构体和元胞数组采用不同的方式:函数返回一个结构体或一个元胞数组,调用方随后再选择其中的字段或元素。
定义并调用具有多个输出的函数
函数签名会列出每个输出的名称,函数体则为每个输出赋值。在 MATLAB 中,命名函数可以采用以下形式:function [sumValue, diffValue, productValue] = calculate(a, b)。下面这个自包含的 Octave 示例使用匿名函数句柄和 deal,让三输出调用可以在一个脚本中运行,同时保留原有计算过程。
运行以下示例。示例输出中的 sum、difference 和 product 标签保持英文,以保留代码与输出块的原始内容。
本节中的代码以及显示的标签或输出仍为英文。
calculate = @(a, b) deal(a + b, a - b, a * b);
[sumValue, diffValue, productValue] = calculate(5, 3);
printf("sum = %d\ndifference = %d\nproduct = %d\n", sumValue, diffValue, productValue);
sum = 8
difference = 2
product = 15
函数句柄按顺序返回和、差与乘积。调用方也按相同顺序将它们赋给 sumValue、diffValue 和 productValue。若要使用独立的 MATLAB 函数,请将命名函数保存在与函数同名的文件中;上面展示的语法明确声明了三个输出变量。
仅接收需要的输出
如果函数返回 [first, second, third],调用时只赋给两个变量,就会接收前两个输出,而不请求第三个输出。若要保留第三个值并忽略第二个值,可使用 [first, ~, third] = functionName(inputs)。波浪号是输出位置的占位符,不会改变函数的计算过程。
应根据任务选择要请求的输出数量和位置。如果只需要一个结果,而且它是第一个输出,赋给一个变量即可。如果需要后面的输出,就要为前面的输出位置添加占位符。如果某个值被赋给了错误的变量,请检查函数声明:MATLAB 按位置对应输出,而不是按调用方的变量名称对应。
用结构体或元胞数组组合相关结果
如果结果具有有意义的名称,或共同表示一条记录,可以返回结构体。例如,函数可以赋值 result.total = a + b 和 result.count = 2,然后只声明 function result = summarize(a, b)。调用方接收一个值,再读取 summary.total 或 summary.count。命名字段能让含义在使用处一目了然;添加相关字段时,也不必扩展多输出调用的签名。
元胞数组同样是一个输出,适合组合类型不同或按位置访问更自然的项目。函数可以创建 items = {a + b, a - b, "computed"} 并返回 items;调用方可以用花括号读取元素内容,例如 result{1}。由于位置没有描述性名称,应说明每个位置的含义;如果读者需要不依赖索引就能识别各项,结构体会更合适。
结构体和元胞数组本身都不会创建多个函数输出。在这些示例中,函数签名仍然只有一个输出变量;只是返回的值中包含了多个数据项。
选择合适的输出方式
当每个结果都有明确且可预测的用途,并且调用方通常只需要其中一部分时,适合使用彼此独立的输出,例如一个值及其状态。输出顺序是函数接口的一部分,因此应保持稳定并加以说明。如果这些值共同构成一条带名称的记录,尤其是描述性字段名能让调用更易理解时,可以使用结构体。如果按位置组织数据很方便,且其中的成员类型可能不同,则可以使用元胞数组。
选择方式时应考虑调用方如何使用数据,而不要假设某种方式更快。如果输出数量或含义随模式变化,可以考虑采用形状一致的结构体,以免调用方猜测各个位置的含义。
常见错误与排查方法
- **请求的输出未赋值:**确保函数的每条执行路径都会为调用方可能请求的每个输出赋值。
- **值出现在错误的变量中:**对照函数输出列表与调用方赋值列表的顺序;变量名称不会决定两者之间的对应关系。
- **调用请求了过多输出:**让请求的输出数量与函数定义一致,或者同时更新函数定义及其调用方。
- **把组合结果当作独立输出:**返回
result的函数只有一个输出。结构体使用result.field访问字段,元胞数组使用result{index}访问元素。 - **要取得后续输出,却必须保留不需要的中间输出:**在该位置放入
~,后续输出仍保持声明时的位置。
排查问题时,应一并检查函数签名、对输出变量的赋值,以及调用方左侧的赋值列表。通常这样就能判断问题是缺少赋值、输出数量不匹配,还是对顺序的假设有误。