В Chapel мы можем легко установить значение по умолчанию формальных аргументов функции, например,
proc test( a = 1, b = 2.0, c = "hi" ) {
...
}
и вызвать функцию, используя также ключевые слова:
test( 10 ); // a = 10, b = 2.0, c = "hi"
test( b = 3.14 ); // a = 1, b = 3.14, c = "hi"
test( c = "yo" ); // a = 1, b = 2.0, c = "yo"
Здесь,Мне интересно, возможно ли определить ключевое слово аргумента, которое не требует предопределенного значения по умолчанию.Более конкретно, я хотел бы написать функцию, которая может дополнительно принимать массив в зависимости от случаев (например, для сохранения промежуточных данных).Здесь единственным требованием является то, что я могу проверить, передан ли фактический аргумент или нет, и нет необходимости указывать значение массива по умолчанию.Я представлял что-то вроде
proc test( ..., optional d: [] real ) {
if present( d ) then ...;
}
or
proc test( ..., d: [] real = None ) {
if present( d ) then ...;
}
, но не смог найти похожие вещи.На данный момент мой обходной путь - дать какое-то фиктивное значение по умолчанию и проверить их свойства, чтобы определить, передан ли фактический аргумент.
proc test( arr = empty2Dreal ) { ... } // where "empty2Dreal" is a pre-defined global array
or
proc test( arr = reshape( [0.0], {1..1,1..1} ) ) { ... } // some dummy array
}
Однако мне интересно, может ли быть более элегантный (?)или идиоматический (?) подход ...
Редактировать
Как предлагается в комментарии, также удобно перегружать несколько функций для получения различных интерфейсов, но в какой-то момент, я думаю, мне нужнопередать какой-нибудь "фиктивный" объект в последнюю (полноценную) подпрограмму и попросить последнюю посмотреть, является ли переданный объект "фиктивным" или нет ... MWE выглядит примерно так:
const empty1Dint: [1..0] int;
proc test( x: real, arr: [] int )
{
writeln("test() with 2 args");
writeln(( x, arr ));
// here, I need to check whether the passed object is
// an actual array or not by some predefined rule
if arr.size > 0 then writeln("got a non-empty array");
}
proc test( x: real )
{
writeln("test() with 1 arg");
test( x = x, arr = empty1Dint );
}
var work = [1,2,3,4,5];
test( x = 1.0 );
writeln();
test( x = 1.0, arr = work );
, которыйдает
test() with 1 arg
test() with 2 args
(1.0, )
test() with 2 args
(1.0, 1 2 3 4 5)
got a non-empty array
Соответствующей версией по умолчанию является
const empty1Dint: [1..0] int;
proc test( x: real, arr: [] int = empty1Dint )
{
writeln("test() with 2 args");
writeln(( x, arr ));
if arr.size > 0 then writeln("got a non-empty array");
}
var work = [1,2,3,4,5];
test( x = 1.0 );
writeln();
test( x = 1.0, arr = work );
, которая дает
test() with 2 args
(1.0, )
test() with 2 args
(1.0, 1 2 3 4 5)
got a non-empty array
Хотя вышеуказанный подход работает для массивов, правило необходимо изменитьв зависимости от типа используемых объектов.Итак, мне было интересно, существует ли какой-то систематический способ, например, передать «нулевой указатель» или какой-то уникальный глобальный объект, чтобы сообщить конечной процедуре о наличии фактических данных.(Но, как отмечалось выше, вышеуказанный подход работает для массивов).
Edit 2
Другой подход может заключаться в простой передаче дополнительного флага для использования переданного массива (тогда в этом нет необходимости).много думать о природе объекта по умолчанию, поэтому может быть в целом проще ...)
const empty1Dint: [1..0] int;
proc test( x: real, arr: [] int = empty1Dint, use_arr = false )
{
writeln( "x= ", x );
if use_arr {
writeln("working with the passed array...");
for i in 1..arr.size do arr[ i ] = i * 10;
}
}
test( x = 1.0 );
writeln();
var work: [1..5] int;
test( x = 2.0, arr = work, use_arr = true );
writeln( "work = ", work );
Редактировать 3
После варианта 3 в ответе, здесь измененная версиямой код, используя _void
и void
:
proc test( x: real, arr: ?T = _void )
{
writeln( "\ntest():" );
writeln( "x = ", x );
writeln( "arr = ", arr );
writeln( "arr.type = ", arr.type:string );
writeln( "T = ", T:string );
if arr.type != void {
writeln( "doing some checks" );
assert( isArray( arr ) );
}
if arr.type != void {
writeln( "writing arr" );
for i in 1..arr.size do arr[ i ] = i * 10;
}
}
// no optional arg
test( x = 1.0 );
// use an optional arg
var work: [1..5] int;
test( x = 2.0, arr = work );
writeln( "\nmain> work = ", work );
Результат:
test():
x = 1.0
arr =
arr.type = void
T = void
test():
x = 2.0
arr = 0 0 0 0 0
arr.type = [domain(1,int(64),false)] int(64)
T = [domain(1,int(64),false)] int(64)
doing some checks
writing arr
main> work = 10 20 30 40 50