Наргин против существует
Для такой функции, как:
function foo(myParam)
if nargin<1
myParam = 'default value';
end % if
end % function
Я видел, что вместо версии nargin люди использовали что-то вроде следующего:
if ~exist('myParam', 'var')
myParam = 'default value';
end %if
Мне интересно, есть ли какие-либо предпочтения в любом случае?
Версия "~ exist..." для меня имеет то преимущество, что если я изменю порядок параметров моей функции, она должна работать. Однако моя озабоченность этим подходом заключается в том, что я могу случайно перехватить переменные, которые определены глобально или в пределах окружения в случае вложенных функций.
Любые мысли по этому вопросу?
Ответы
Ответ 1
Оба должны работать. Но...
Exist имеет тенденцию быть медленным, так как он должен просматривать ваше рабочее пространство для рассматриваемой переменной. Когда вы пишете ошибки проверки, как это, вы не хотите, чтобы они всасывали циклы процессора. Тест против наргина - это простой тест против единственного числового значения.
Я бы также предложил более обширный тест. Что-то вроде
if (nargin<1) || isempty(myparam)
myparam = defaultvalue;
elseif
...
end
Внутри ветки elseif я положу набор дополнительных тестов, чтобы увидеть, есть ли у параметра ожидаемый размер, форма, класс переменной и т.д. Если эти тесты терпят неудачу, я верну приветственное сообщение об ошибке, которое объясняет что не так.
Ответ 2
Я пошел бы с наргином по двум причинам:
-
Если вы измените порядок параметров на свою функцию, исправление кода проверки ввода будет наименьшим из ваших проблем; вам также придется обновлять все сайты вызовов до вашей функции.
-
Наргин намного дешевле. существуют, даже если они ограничены, чтобы просто проверять переменные, необходимо отсканировать всю рабочую область, выполняя ряд сравнений строк на этом пути. метод наргина состоит только из скаляра, меньшего чем операция.
Ответ 3
Я всегда проверяю аргументы с помощью nargchk
, а затем перехожу с тегами nargin
, как и они. Как отмечали другие, они дешевле, и я думаю, что яснее.
В функциях, которые, как я ожидаю, будут повторно использоваться в значительной степени, я всегда ставил перед собой много проверок, а затем структурировал код для вызова реальной реализации позже.
Я также склонен структурировать необязательные аргументы (если не использовать varargin
) следующим образом:
function x = myfcn( arg1, opt_arg2 )
if nargin < 2
arg2 = 'default';
else
arg2 = opt_arg2;
end
как я думаю, это делает его более очевидным при редактировании файла, аргументы которого будут необязательными.
Ответ 4
Я бы пошел с опцией NARGIN по причинам, указанным SCFrench. Еще одно преимущество: я часто использую его в сочетании с выражением SWITCH, когда у меня есть более двух входных аргументов:
function outArgs = my_fcn(inArg1,inArg2,inArg3)
switch nargin,
case 0, % No input case
error('Not enough inputs!');
case 1, % Set last 2 inputs to default
inArg2 = 'yes';
inArg3 = 'on';
case 2, % Set last input to default
inArg3 = 'on';
end
...
% Checking of variable types and values would go here!
...
end
Ответ 5
Для тех, кто использует MATLAB R2007b или более поздней версии, здесь лучший ответ: InputParser
Это избавляет от необходимости синхронизировать любое добавление, удаление, переименование и переупорядочение аргументов.
(Сколько вы сохраните будет зависеть от вашего стиля кодирования, но нет более аккуратного способа, чем InputParser.)
Я не тестировал его на скорость, но если вы используете более 1000 миллисекунд для запуска, нет причин беспокоиться о скорости работы InputParser.
Пример:
function AbCdEfGhIj(ffff, ggggg, varargin)
opts = inputParser;
opts.addRequired('ffff', @(p)(ischar(p) && size(p,1)==1 || iscell(p)));
opts.addRequired('ggggg', @(p)(iscell(p) && all(cellfun(@ischar,p))));
opts.addOptional('Recursive', false, @islogical);
opts.addOptional('IncludeFullPath', logical([]), @islogical);
opts.parse(ffff, ggggg, varargin{:});
opts = opts.Results;
if isempty(opts.IncludeFullPath),
opts.IncludeFullPath = iscell(opts.fffff) || opts.Recursive;
end
Ответ 6
Я предпочитаю exist
по опции nargin
по двум причинам.
1.
После прочтения большого количества кода от людей, которые никогда не учились оглядываться на свой собственный код, я только почувствовал себя сильнее, потому что exist
делает код читаемым.
Например, я столкнулся с такой функцией. Для вашего удобства я дал переменные разумные имена:
[model, accuracy] = epicModelingFunction (dataMatrix, responseVector, indicatorForCategoricalVariables, optionsForInternalFunctions, typeOfDistanceCalculation, notationForMissingValues, isClassificationAndNotRegression, scalingMethod, shouldPlotAllIntermediateStuff)
% EPICMODELINGFUNCTION is actually a horrible function to read and not epic at all
% ...
За этим последовал if nargin < n
для каждой переменной, отличной от первых двух. Единственная причина, по которой я мог бы следить за тем, что должен иметь nargin(n)
, не считая ввода заголовка, состоит в том, что за if nargin < n
всегда следовали (только иногда несколько строк кода) и объявление отсутствующего ввода со значением по умолчанию. Для больших патронов кода в if nargin < n
я определенно потеряю трек.
2. exist
на самом деле не проверяет полное рабочее пространство, если вызвано функцией. Конечно, сравнение двух чисел дешевле, чем сравнение нескольких строк, но если они используются в начале функции для заполнения значений по умолчанию для не заданных параметров, это нормально. Рассмотрим следующую функцию:
function testExist(C)
if exist('B', 'var')
disp('''exist'' in a function checks the workspace.')
elseif exist('C', 'var')
disp('''exist'' in a function ignores the variables in the workspace, but checks the function space.')
else
disp('''exist'' is broken or no parameter was given.')
end
end
И затем выполните следующее:
A = magic(3);
B = magic(4);
testExist(A)
приводит к этому результату:
'exist' in a function ignores the variables in the workspace, but checks the function space.