【问题标题】:Using a function with optional inputted parameters使用带有可选输入参数的函数
【发布时间】:2019-02-06 21:16:11
【问题描述】:

我已经为这个问题苦苦挣扎了大约一个星期。我一直在尝试将脚本转换为用于研究目的的函数。问题是代码有很多条件变量的现有语句,所以某些变量在检查时不会存在于工作区中(这就是它作为脚本运行良好的原因)。

Varargin 不能解决这个问题,因为某些函数 INPUTS 将不存在。

工作区

var1 = 1
var2 = 2
var4 = 4

转成函数的代码

if exist('var3','var')
   disp('var 3 exists')
else
   disp('var 3 does not exist')
end

以下函数将不起作用,因为它正在调用不存在的变量 3。

调用函数

runCode(var1, var2, var3, var4)

我最初在我的函数之前编写了此代码,并为isnan 而不是exist 进行了代码检查,但这不是很好的做法,而且由于该函数经常被调用,我不想更新此函数设置每当更改代码时。

  if ~exist("var1", "var"), var1= NaN; end 
  if ~exist("var2", "var"), var2= NaN; end 
  if ~exist("var3", "var"), var3= NaN; end 
  if ~exist("var4", "var"), var4= NaN; end 

我不想使用eval,加载工作区给我带来了问题,因为存在一堆数字,并且在后面的代码部分中会弄乱数字计数。我唯一知道的想法是为前面的 if 语句设置一个设置脚本,或者以某种方式将所有工作区数据保存到一个结构或其他东西中,然后将值分配给相应的 who 字符串(给出工作区变量名称)。

感谢你们提出的任何想法

【问题讨论】:

  • 所以你的函数中有一堆变量,它们可能存在于工作区中,也可能不存在。如果您的代码依赖于这些变量的存在,您将别无选择,只能检查它们是否存在,如果不存在则创建它们。没有办法解决这个问题。我个人会用函数包装变量的每次出现,例如runCode( safevar(var1), safevar(var2), safevar(var3), safevar(var4) ) 并检查 safevar 中是否存在,如果不存在则通过 eval 创建变量。
  • 我会使用 inputParser 对象来解决这个问题。您可以指定名称-值对,以便调用函数runCode('var1', var1, 'var3', var3, ...) 并让 inputParser 为任何未输入的var# 分配默认值。除了使用名称值对之外,输入解析器还允许您扩展结构,因此您可以拥有一个带有字段名的结构,{'var1', 'var3'} then pass the struct into runCode(S)`。另见this answer
  • “加载工作区给我带来了问题,因为存在一堆数字,它会在代码的后面部分弄乱数字计数。”我不明白这一点。一些代码取决于是否有图窗打开?您无法解决将代码更改为函数的问题,图形窗口是全局事物,基础工作区和您调用的函数的工作区中的计数相同。
  • 据我了解,您有一个脚本根据存在的变量执行不同的操作。您也可以在函数中执行此操作,使用 evalin,但我不知道这是否比保留脚本更好。我没有看到任何其他解决方法。函数应该只读取传递给它的值,因此您需要使用相关变量调用函数。无论是否定义了变量,它的行为都不应该有所不同。我会说保留它作为脚本!

标签: matlab function scripting optional-parameters variable-declaration


【解决方案1】:

当前脚本的行为会有所不同,具体取决于是否存在一组具有预定义名称的变量。这很难在函数中复制,因为函数不应该读取调用工作区的值。当然可以这样做:

try
   var1 = evalin('caller','var1');
catch
   % do nothing, the variable doesn't exist in the caller, it won't exist here
end

但这真的不好的做法,和脚本没有什么不同。而且OP特别说不想用eval

还有一个替代方案,我不太愿意推荐它,因为它几乎和上面的一样邪恶。我们将定义一个函数,其输入参数不是基于顺序,而是基于名称:

runCode(var1)

行为会不同于

runCode(var2)

但以下两个语句的行为相同:

runCode(var1,var2)
runCode(var2,var1)

被淘汰了?你应该是!

诀窍是使用inputname,如下所示:

function runCode(varargin)
for ii = 1:nargin
   switch inputname(ii)
      case 'var1', var1 = varargin{ii};
      case 'var2', var2 = varargin{ii};
      case 'var3', var3 = varargin{ii};
      case 'var4', var4 = varargin{ii};
      otherwise,   error('Illegal input argument')
   end
end

函数的其余部分将是 OP 脚本的主体,其中包含如下代码:

if exist('var1','var')
   % ...
end

也就是说,首先我们看哪些变量被传递给函数,然后我们看哪些变量存在。应该可以重写脚本本身来替换 exist 检查输入参数名称列表。

【讨论】:

    【解决方案2】:

    您可以将输入设置为 arg 对,因此您可以这样称呼它:

    runCode ( 'var1', 123, 'var2', 456, 'var4', 789)
    

    你的功能在哪里

    function runCode ( varargin )
      defaults.var1 =[];
      defaults.var2 =[];
      defaults.var3 =[];
      defaults.var4 =[];
    
      for ii = 1:2:nargin
        if isfield ( defaults, varargin{ii} )
          defaults.(varargin{ii}) = varargin{ii+1};
        else
          Throw error?
        end
    

    然后你更改对 var3 的检查以检查值 defaults.var3 是否为空。

    【讨论】:

      【解决方案3】:

      感谢所有反馈。由于我想调用的函数有时是从同一个地方调用的,但存在不同的变量,所以我无法改变参数的设置方式。所以,我所做的可能会让你们哭泣,但我有一个设置脚本,我在检查参数是否存在的函数之前调用它,如果不存在则将它们设置为 NaN。它与我之前的解决方案完全相同,但在脚本中。

      PS 我同意这应该是一个脚本,但他们真的希望它是一个函数¯_(ツ)_/¯

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-13
        • 2011-04-28
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-06
        相关资源
        最近更新 更多