11.3 Множественные возвращаемые значения
В отличие от многих других языков программирования, Octave позволяет определять функции, возвращающие более одного значения. Синтаксис определения функций, возвращающих несколько значений, таков:
function [ret-list] = name (arg-list) body endfunction
где имя, список аргументов и тело имеют то же значение, что и раньше, а список возвращаемых значений — это список переменных, разделённых запятыми, которые будут хранить значения, возвращаемые функцией. Список возвращаемых значений должен содержать хотя бы одно значение. Если список возвращаемых значений содержит только одно значение, эта форма оператора function эквивалентна форме, описанной в предыдущем разделе.
Вот пример функции, возвращающей два значения: максимальный элемент вектора и индекс его первого вхождения в вектор.
function [max, idx] = vmax (v)
idx = 1;
max = v (idx);
for i = 2:length (v)
if (v (i) > max)
max = v (i);
idx = i;
endif
endfor
endfunction В этом конкретном случае два значения могли бы быть возвращены как элементы одного массива, но это не всегда возможно или удобно. Возвращаемые значения могут иметь несовместимые размеры, и часто желательно присваивать индивидуальные имена каждому возвращаемому значению.
Можно использовать функцию nthargout для получения только некоторых возвращаемых значений или нескольких значений сразу в массиве ячеек. См. Массивы ячеек.
- nthargout (n, func, …)
- nthargout (n, ntot, func, …)
-
Возвращает n-й аргумент вывода функции, указанной с помощью дескриптора функции или строки func.
Любые дополнительные аргументы передаются напрямую функции func. Общее количество аргументов для вызова func можно передать в ntot; по умолчанию ntot равно n. Входной параметр n также может быть вектором индексов вывода, в этом случае выводом будет массив ячеек запрошенных аргументов вывода.
Предполагаемое использование
nthargout— это избежание промежуточных переменных. Например, при поиске индексов максимального элемента матрицы следующие два составных оператора nthargoutm = magic (5); cell2mat (nthargout ([1, 2], @ind2sub, size (m), nthargout (2, @max, m(:)))) ⇒ 5 3полностью эквивалентны следующим строкам:
m = magic (5); [~, idx] = max (M(:)); [i, j] = ind2sub (size (m), idx); [i, j] ⇒ 5 3
Также может быть полезно иметь все аргументы вывода в одной ячейке следующим образом:
USV = nthargout ([1:3], @svd, hilb (5));
Помимо установки nargin каждый раз, когда вызывается функция, Octave также автоматически инициализирует nargout значением, которое соответствует количеству ожидаемых возвращаемых значений. Это позволяет создавать функции, которые ведут себя по-разному в зависимости от числа значений, запрошенных пользователем функции. Неявное присвоение встроенной переменной ans не учитывается при подсчёте аргументов вывода, поэтому значение nargout может быть нулевым.
Функции svd и lu являются примерами встроенных функций, которые ведут себя по-разному в зависимости от значения nargout.
Можно написать функции, которые устанавливают только некоторые возвращаемые значения. Например, вызов функции
function [x, y, z] = f () x = 1; z = 2; endfunction
как
[a, b, c] = f ()
выводит:
a = 1 b = [](0x0) c = 2
вместе с предупреждением.
- nargout ()
- nargout (fcn)
-
Отчёт о количестве аргументов вывода функции.
Вызванная изнутри функции, возвращает количество значений, которые вызывающая сторона ожидает получить. На верхнем уровне
nargoutбез аргумента не определена и вызовет ошибку.Если вызывается с необязательным аргументом fcn — именем или дескриптором функции — возвращает количество объявленных значений вывода, которые функция может произвести.
Если последним аргументом вывода является varargout, возвращаемое значение является отрицательным.
Например,
f ()
приведёт к тому, что
nargoutвернёт 0 внутри функцииf, и[s, t] = f ()
приведёт к тому, что
nargoutвернёт 2 внутри функцииf.Во втором случае
nargout (@histc) # or nargout ("histc") using a string inputвернёт 2, так как у
histcдва выхода, в то время какnargout (@imread)
вернёт -2, так как у
imreadдва выхода, а второй является varargout.Замечание по программированию.
nargoutне работает для встроенных функций и возвращает -1 для всех анонимных функций.
Хорошей практикой в начале функции является проверка правильности её вызова. В Octave часто встречается следующая конструкция:
if (nargin < min_#_inputs || nargin > max_#_inputs) print_usage (); endif
которая останавливает выполнение функции и выводит сообщение о правильном способе вызова функции всякий раз, когда количество входов неверно.
Для совместимости с MATLAB, narginchk и nargoutchk доступны, которые обеспечивают аналогичную проверку ошибок.
- narginchk (minargs, maxargs)
-
Проверка правильности количества входных аргументов.
Генерирует сообщение об ошибке, если количество аргументов в вызывающей функции находится вне диапазона minargs и maxargs. В противном случае ничего не делает.
И minargs, и maxargs должны быть скалярными числовыми значениями. Нулевые, бесконечные и отрицательные значения допустимы, и minargs и maxargs могут быть равными.
Обратите внимание, что эта функция вычисляет
narginдля вызывающей стороны.См. также: nargoutchk, error, nargout, nargin.
- nargoutchk (minargs, maxargs)
- msgstr = nargoutchk (minargs, maxargs, nargs)
- msgstr = nargoutchk (minargs, maxargs, nargs, "string")
- msgstruct = nargoutchk (minargs, maxargs, nargs, "struct")
-
Проверка правильности количества аргументов вывода.
В первой форме возвращает ошибку, если количество аргументов не находится в диапазоне от minargs до maxargs. В противном случае ничего не делает. Обратите внимание, что эта функция вычисляет значение
nargoutдля вызывающей стороны, поэтому его значение не должно быть изменено.И minargs, и maxargs должны быть числовыми скалярами. Нулевые, бесконечные и отрицательные значения допустимы, и они могут иметь одинаковое значение.
Для обратной совместимости другие формы возвращают соответствующее сообщение об ошибке (или структуру), если количество запрошенных выходов недопустимо.
Это полезно для проверки того, что количество аргументов вывода, предоставленных функции, находится в приемлемом диапазоне.
Помимо количества аргументов, входы могут быть проверены на различные свойства. validatestring используется для строковых аргументов, а validateattributes для числовых аргументов.
- validstr = validatestring (str, strarray)
- validstr = validatestring (str, strarray, funcname)
- validstr = validatestring (str, strarray, funcname, varname)
- validstr = validatestring (…, position)
-
Проверка того, что str является элементом или подстрокой элемента в strarray.
Когда str — это строка символов, подлежащая проверке, а strarray — это ячейка str, содержащая допустимые значения, то validstr будет валидированной формой str, где валидация определена как str — член или подстрока validstr. Это полезно как для проверки, так и для расширения коротких опций, таких как
"r", до их длинных форм, таких как"red". Если str является подстрокой validstr, а совпадений несколько, то будет возвращено самое короткое совпадение, если все совпадения являются подстроками друг друга. В противном случае будет выведена ошибка, поскольку расширение str неоднозначно. Все сравнения нечувствительны к регистру.Дополнительные входные данные funcname, varname и position являются необязательными и сделают сообщение об ошибке валидации более конкретным.
Примеры:
validatestring ("r", {"red", "green", "blue"}) ⇒ "red" validatestring ("b", {"red", "green", "blue", "black"}) ⇒ error: validatestring: multiple unique matches were found for 'b': blue, blackСм. также: strcmp, strcmpi, validateattributes, inputParser.
- validateattributes (A, classes, attributes)
- validateattributes (A, classes, attributes, arg_idx)
- validateattributes (A, classes, attributes, func_name)
- validateattributes (A, classes, attributes, func_name, arg_name)
- validateattributes (A, classes, attributes, func_name, arg_name, arg_idx)
-
Проверка валидности входного аргумента.
Подтверждает, что аргумент A является допустимым, принадлежа к одному из classes и содержит все attributes. Если это не так, генерируется ошибка с соответствующим сообщением. Сообщение об ошибке может быть дополнено именем функции fun_name, именем аргумента arg_name и его позицией в входном массиве arg_idx.
classes должен быть массивом ячеек строк (разрешен пустой массив ячеек) с именами классов (помните, что имя класса чувствительно к регистру). В дополнение к имени класса также допустимы следующие категории:
"float"-
Значение с плавающей точкой, включающее классы
"double"и"single". "integer"-
Целое значение, включающее классы (u)int8, (u)int16, (u)int32, (u)int64.
"numeric"-
Числовое значение, включающее либо значение с плавающей точкой, либо целое значение.
attributes должен быть массивом ячеек с именами проверок для A. Некоторые из них требуют дополнительного значения, предоставляемого сразу после имени (см. подробности ниже для каждого).
"<="-
Все значения меньше или равны следующему значению в attributes.
"<"-
Все значения меньше следующего значения в attributes.
">="-
Все значения больше или равны следующему значению в attributes.
">"-
Все значения больше следующего значения в attributes.
"2d"-
Двумерная матрица. Обратите внимание, что векторы и пустые матрицы имеют 2 измерения, одно из которых имеет длину 1, или оба длину 0.
"3d"-
Не имеет более 3 измерений. Двумерная матрица — это 3-мерная матрица, третье измерение которой имеет длину 1.
"binary"-
Все значения равны 1 или 0.
"column"-
Значения расположены в одном столбце.
"decreasing"-
Ни одно значение не равно NaN, и каждое меньше предыдущего.
"diag"-
Значение — диагональная матрица.
"even"-
Все значения — чётные числа.
"finite"-
Все значения конечны.
"increasing"-
Ни одно значение не равно NaN, и каждое больше предыдущего.
"integer"-
Все значения — целые. Это отличается от использования
isinteger, которое проверяет только целочисленный тип. Это проверяет, что каждое значение в A является целым значением, т. е. не имеет десятичной части. "ncols"-
Содержит ровно столько столбцов, сколько указано в следующем значении attributes.
"ndims"-
Содержит ровно столько измерений, сколько указано в следующем значении attributes.
"nondecreasing"-
Ни одно значение не равно NaN, и каждое больше или равно предыдущему.
"nonempty"-
Не пусто.
"nonincreasing"-
Ни одно значение не равно NaN, и каждое меньше или равно предыдущему.
"nonnan"-
Ни одно значение не является
NaN. "nonnegative"-
Все значения неотрицательны.
"nonsparse"-
Не является разреженной матрицей.
"nonzero"-
Ни одно значение не равно нулю.
"nrows"-
Содержит ровно столько строк, сколько указано в следующем значении attributes.
"numel"-
Содержит ровно столько элементов, сколько указано в следующем значении attributes.
"odd"-
Все значения — нечётные числа.
"positive"-
Все значения положительны.
"real"-
Это матрица без комплексных чисел.
"row"-
Значения расположены в одной строке.
"scalar"-
Это скаляр.
"size"-
Размер имеет длину, равную значениям следующего в attributes. Следующее значение должно быть массивом с длиной для каждого измерения. Чтобы пропустить проверку для определенного измерения, можно использовать значение
NaN. "square"-
Это квадратная матрица.
"vector"-
Значения расположены в одном векторе (столбце или строке).
См. также: isa, validatestring, inputParser.
Если ни одна из предыдущих функций не подходит, существует также класс inputParser, который может выполнять чрезвычайно сложную проверку входных данных для функций.
- p = inputParser ()
-
Создать объект p класса inputParser.
Этот класс разработан для простого парсинга аргументов функций. Класс поддерживает четыре типа аргументов:
- обязательные (см.
addRequired); - необязательные (см.
addOptional); - именованные (см.
addParameter); - переключатели (см.
addSwitch).
После определения API функции этими методами предоставленные аргументы можно обработать методом
parse, а результаты парсинга получить с помощью аксессораResults. - обязательные (см.
- inputParser.Parameters
-
Возвращает список имен параметров, которые уже определены.
- inputParser.Results
-
Возвращает структуру с именами аргументов в качестве имен полей и соответствующими значениями.
- inputParser.Unmatched
-
Возвращает структуру, аналогичную
Results, но для неопределенных параметров. См. свойствоKeepUnmatched.
- inputParser.UsingDefaults
-
Возвращает массив ячеек с именами аргументов, которые используют значения по умолчанию.
- inputParser.CaseSensitive = boolean
-
Устанавливает, чувствителен ли поиск соответствий имен аргументов к регистру. По умолчанию — false.
- inputParser.FunctionName = name
-
Устанавливает имя функции, которое будет использоваться в сообщениях об ошибках; по умолчанию — пустая строка.
- inputParser.KeepUnmatched = boolean
-
Устанавливает, должна ли генерироваться ошибка для неопределенных аргументов. По умолчанию — false. Если установлено в true, дополнительные аргументы можно получить через
Unmatchedпосле методаparse. Обратите внимание, что поскольку аргументыSwitchиParameterмогут быть смешаны, невозможно определить тип несопоставленных. Если аргумент не найден, он предполагается как типаParameterи ожидается, что за ним последует значение.
- inputParser.StructExpand = boolean
-
Устанавливает, можно ли передать структуру функции вместо пар «параметр/значение». По умолчанию — true.
Следующий пример демонстрирует использование этого класса:
function check (varargin) p = inputParser (); # create object p.FunctionName = "check"; # set function name p.addRequired ("pack", @ischar); # mandatory argument p.addOptional ("path", pwd(), @ischar); # optional argument ## create a function handle to anonymous functions for validators val_mat = @(x) isvector (x) && all (x <= 1) && all (x >= 0); p.addOptional ("mat", [0 0], val_mat); ## create two arguments of type "Parameter" val_type = @(x) any (strcmp (x, {"linear", "quadratic"})); p.addParameter ("type", "linear", val_type); val_verb = @(x) any (strcmp (x, {"low", "medium", "high"})); p.addParameter ("tolerance", "low", val_verb); ## create a switch type of argument p.addSwitch ("verbose"); p.parse (varargin{:}); # Run created parser on inputs ## the rest of the function can access inputs by using p.Results. ## for example, get the tolerance input with p.Results.tolerance endfunctioncheck ("mech"); # valid, use defaults for other arguments check (); # error, one argument is mandatory check (1); # error, since ! ischar check ("mech", "~/dev"); # valid, use defaults for other arguments check ("mech", "~/dev", [0 1 0 0], "type", "linear"); # valid ## following is also valid. Note how the Switch argument type can ## be mixed into or before the Parameter argument type (but it ## must still appear after any Optional argument). check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high"); ## following returns an error since not all optional arguments, ## `path' and `mat', were given before the named argument `type'. check ("mech", "~/dev", "type", "linear");Примечание 1: Функция может иметь любое сочетание четырёх типов API, но они должны появляться в определённом порядке. Аргументы
Requiredдолжны быть первыми и могут быть последованные любыми аргументамиOptional. Только аргументыParameterиSwitchмогут быть смешаны вместе, и они должны находиться в конце.Примечание 2: Если в API функции смешаны аргументы
OptionalиParameter, то как только строковый необязательный аргумент не пройдёт валидацию, он будет считаться концом аргументовOptional. Остальные аргументы будут сравниваться с любыми аргументамиParameterилиSwitch.См. также: nargin, validateattributes, validatestring, varargin.
© 1996–2022 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v5.2.0/Multiple-Return-Values.html