如何在MATLAB中制作标记值?

时间:2014-02-28 18:55:30

标签: matlab

以下Python中的示例可能有助于说明“哨兵值”的含义:

SENTINEL = object()
def foo(opt=SENTINEL):
    if opt is SENTINEL:
        opt = make_me_fresh_default_opt_please()
    # etc

在上面的代码片段中,变量SENTINEL被初始化为一个全新的“nonce”对象,该对象在其定义的文件之外的任何其他位置都没有内容,也没有任何可想象的含义。 foo是一个带有可选参数opt的函数。 SENTINEL常量foo用于一件事,只有一件事:来测试没有参数调用的条件。这是通过if opt is SENTINEL完成的。

要了解为什么人们会想要像SENTINEL这样便宜的“随机数”常量,将上面的代码段与使用标准Python值(None)的代码段进行对比,以测试无争论条件:

def foo2(opt=None):
    if opt is None:
        opt = make_me_fresh_default_opt_please()
    # etc

此函数foo2无法区分 1 下的两个调用:

foo2()
foo2(None)

所以,总而言之,“sentinel”在这里我的意思是一个代码的其余部分未知的常量值,其唯一目的是作为某些条件的布尔测试的基础。

在MATLAB中是否有一种类似的简单方法来生成这样的标记常量?

编辑:我想强调一点,我的问题严格关于如何创建哨兵,留下使用这种哨兵的目的问题。我提供了一个具体而合理的例子,说明为什么人们可能想要这样一个哨兵不变,部分是为了确保帖子的读者能够知道“哨兵”一词的含义。在这个例子中,sentinel 刚刚发生用于测试“无参数传递”条件,但是有许多其他可能的条件,人们可能想要使用sentinel值进行测试。所以,这个问题,重点是,不是关于测试“无参数通过”条件,而是关于生成标记常数的问题,一般来说。

EDIT2:基于Notlikethat和Bas Swinckels的回答:

function y = foo(varargin)
    p = inputParser;
    p.addParameter('Opt', @DEFAULT);
    p.parse(varargin{:});

    opt = p.Results.Opt;
    if DEFAULT(opt)
        opt = rand();
    end

    y = opt;
    % etc
end

function its_me = DEFAULT(opt)
    its_me = isequal(opt, @DEFAULT);
end

%{
>> foo('Opt', 3)
ans =
     3
>> foo()
ans =
    0.9134
>> foo
ans =
    0.6324
%}
好的,这可能太可爱了。如果它更接近Notlikethat的原始建议(注意下面的make_sentinel是一个独立的功能),代码既简单又清晰:

% foo.m
function y = foo(varargin)
    DEFAULT = make_sentinel();
    p = inputParser;
    p.addParameter('Opt', DEFAULT);
    p.parse(varargin{:});

    opt = p.Results.Opt;
    if isequal(opt, DEFAULT)
        opt = rand();
    end

    y = opt;
    % etc
end

% make_sentinel.m
function sentinel = make_sentinel()
    sentinel = ...
       @() 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function';
    % or, more conventionally,
    % sentinel = @() 0;
end


>> foo('Opt', 6)
ans =
     6
>> foo()
ans =
    0.9575
>> foo
ans =
    0.9649

并且表明由make_sentinel制作的哨兵确实是独一无二的(而且这种堕落不会付出代价):

>> foo('Opt', make_sentinel())
ans = 
    @()'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function'

1 当然,之前定义的foo无法区分foo()foo(SENTINEL),但是,AFAIC,后者的调用会降低在“反向编程”的范畴内(因为它要求调用代码“走出去”以颠覆被调用代码的意图),我不担心这种反常。相比之下,前面显示的foo2(None)示例说明了在常规编程过程中可能很容易发生的情况,特别是当它的实际源代码类似于foo(some_variable)some_variable时,无意中最终持有标准Python值None

3 个答案:

答案 0 :(得分:3)

一个解决方案几乎就是直接的等价物:

function y = foo(opt)
    %default argument
    if nargin<1
        opt = @SENTINEL;
    end

    %actual check
    if isequal(opt, @SENTINEL)
        opt = make_me_fresh_default_opt_please()
    end

    % etc
end

function SENTINEL  % private function in the same file
end

不可否认,相当这么简单,但与其他任何内容一样,这与Matlab语法一样。

您可能也会作弊并将其基于完全采用相同的方法:

SENTINEL = java.lang.Object;
% etc...

为了更加简单,牺牲保证唯一性,tempname是生成不太可能与有效数据冲突的字符串的简单方法(特别是如果有效数据不是字符串... )

答案 1 :(得分:1)

如果你想在函数调用中确定没有传递参数的“万无一失”的方法,那么使用nargin是习惯性的MATLAB方法。

在函数体中,调用nargin将返回传递给函数的参数个数。所以你可以写代码......

function foo(a, b)
    switch nargin
        case 0
            % Handle the no-argument case...
        case 1
            % Handle the one-argument case...
        otherwise
            % All arguments supplied...
    end
    % Other code here...
end

有关详细信息,请参阅the MATLAB documentation for nargin

答案 2 :(得分:1)

如果你真的想拥有一个独特的哨兵值,你可以创建自己的哨兵类。但我想在任何现实的上下文中,找到一些不能由任何函数或用户输入产生的标准数字/单元格/结构/字符串应该总是微不足道的。这可以像

一样简单
SENTINEL  = 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_string';

使用此值的用户显然属于“反常编程”的定义。使用此函数可以测试变量是否是哨兵:

issentinel = @(var) ischar(var) && strcmp(var, SENTINEL)

还注意inputParser类,它允许您为缺少的参数定义默认值,这可能会减少对标记值的需求。