没有默认值的可选函数参数? [英] Optional function arguments with no default value possible?

查看:109
本文介绍了没有默认值的可选函数参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Chapel中,我们可以轻松设置函数形式参数的默认值,例如,

In Chapel, we can set the default value of function formal arguments easily, for example,

proc test( a = 1, b = 2.0, c = "hi" ) {
    ...
}

并通过同时使用关键字来调用该函数:

and call the function by using keywords also:

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"

在这里,我想知道是否可以定义不需要预定义默认值的关键字参数.更具体地说,我想编写一个函数,该函数可以根据情况选择接收数组(例如,保存中间数据).在这里,唯一的要求是我可以检查是否传递了实际参数,并且不需要给出默认的数组值.我想像像

Here, I am wondering if it is possible to define a keyword argument that does not require a predefined default value. More specifically, I would like to write a function that can optionally receive an array depending on cases (e.g., to save intermediate data). Here, the only requirement is that I can check whether the actual argument is passed or not, and there is no need to give the default array value. I imagined something like

proc test( ..., optional d: [] real ) {
    if present( d ) then ...;
}

or

proc test( ..., d: [] real = None ) {
    if present( d ) then ...;
}

,但是找不到类似的东西.目前,我的解决方法是提供一些虚拟的默认值,并检查其属性以确定是否传递了实际参数.

but was not able to find similar things. At the moment, my workaround is to give some dummy default value and check their properties to determine whether an actual argument is passed.

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
}

但是,我想知道是否会有更优雅的(?)或惯用的(?)方法...

However, I am wondering whether there might be a more elegant(?) or idiomatic(?) approach...

正如评论中所建议的,重载几个函数以获取不同的接口也很方便,但我想在某个时候我需要将一些虚拟"对象传递给最终(成熟的)例程,并询问后者查看传递的对象是否为虚拟" ... MWE是这样的:

As suggested in the comment, it is also convenient to overload several functions to get different interfaces, but at some point I guess I need to pass some "dummy" object to the final (full-fledged) routine and ask the latter to see if the passed object is "dummy" or not... MWE is something like this:

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

尽管以上方法适用于数组,但规则仍需要根据使用的对象类型进行更改.因此,我想知道是否存在某种系统的方法,例如传递空指针"或某些唯一的全局对象,以告知最终例程有关实际数据的存在. (但是,如上所述,以上方法适用于数组).

Although the above approach works for arrays, the rule needs to change depending on the type of objects used. So, I was wondering if there is some systematic way, e.g., to pass a "null pointer" or some unique global object to tell the final routine about the presence of the actual data. (But, as noted above, the above approach works for arrays).

另一种方法可能只是传递一个额外的标志以使用传递的数组(然后,无需考虑默认对象的性质,因此总体上可能会更简单...)

Another approach may be simply to pass an additional flag for using the passed array (then there is no need to think much about the nature of the default object, so may be overall simpler...)

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,这是使用_voidvoid的我的代码的修改版本:

Edit 3

Following Option 3 in the answer, here is a modified version of my code using _void and 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

推荐答案

此答案讨论了3个答案:

This answer discusses 3 answers:

  1. 问题编辑中讨论的策略.
  2. 使用Box类型的策略
  3. 使用具有无效默认值的泛型函数的策略
  1. The strategy discussed in the edit of the question.
  2. A strategy using a Box type
  3. A strategy using a generic function with a void default value

这些选项中我最喜欢的是选项3.

My favorite of these options is Option 3.

proc test( x: real, arr: [] int = empty1Dint, use_arr = false )策略是合理的,如果有些冗长.这里的主要缺点是,如果您不希望呼叫站点必须通过use_arr=trueuse_arr=false,则需要test的更多重载.这是一个执行此操作的简单程序:

proc test( x: real, arr: [] int = empty1Dint, use_arr = false ) strategy described in the question is reasonable, if a little verbose. The main drawback here is that you'd need more overloads of test if you didn't want the call sites to have to pass use_arr=true or use_arr=false. Here is a simple program that does that:

proc test(optional, hasOptional:bool) {
  writeln("in test");
  writeln("  optional is ", optional);
  if hasOptional == false then
    writeln("  note: default was used for optional");
}

proc test(optional) {
  test(optional, hasOptional=true);
}
proc test() {
  var emptyArray:[1..0] int;
  test(emptyArray, hasOptional=false);
}


test();
test([1, 2, 3]);

选项2

另一种替代方法是创建一个类来存储可选参数数据,并在默认情况下传递nil.

Option 2

Another alternative is to create a class to store the optional argument data, and pass nil by default.

class Box {
  var contents;
}

proc makeArray() {
  var A:[1..2] int;
  return A;
}

proc emptyBox() {
  var A:[1..0] int;
  var ret: owned Box(A.type) = nil;
  return ret;
}

proc test( optional=emptyBox() ) {
  writeln("in test with optional=", optional);
}

test();
test(new owned Box(makeArray()));

这里最棘手的部分是makeArray()和emptyBox()返回的数组类型必须匹配.可以使用类型别名来使它们引用相同的数组类型,但是究竟适合哪种类型取决于您的应用程序.这种方法的另一个问题是,它导致在传递此类参数的过程中复制数组.而且,必须考虑Box的销毁位置.是test停留在数组值上(例如,将其存储在数据结构中)还是只是临时使用它?在我的示例中,这是由emptyBox返回的类型设置的.

Here the main tricky part is that the array type returned by makeArray() and emptyBox() have to match. It'd be possible to use a type alias to have them refer to the same array type, but how exactly that would fit in depends on your application. Another problem with this approach is that it causes the array to be copied in the process of passing such an argument. And, one has to think about where the Box will be destroyed. Is test to hang on to the array value (e.g. storing it in a data structure) or just going to use it temporarily? This is set by the type returned by emptyBox in my example.

标准库获得这种Box类型可能是合理的,但现在还没有.

It's probably reasonable for the standard library to gain such a Box type but it doesn't have one now.

我最喜欢的解决此问题的方法是第三个策略. Chapel包含称为_void 的void类型的值.关键是声明proc test( optional:?t=_void ).这里的test是泛型函数-语法argument:?t表示参数可以具有可变的类型(在函数内可以作为t使用).要获得一个也具有默认值的通用参数,这是必需的(否则,该参数将仅具有从默认值推断出的类型).

My favorite solution to this problem is a third strategy altogether. Chapel includes a value of void type called _void. The key is the declaration proc test( optional:?t=_void ). Here test is a generic function - the syntax argument:?t indicates that the argument can have a varied type (which will be available as t within the function). This is necessary to get a generic argument that also has a default value (otherwise the argument will have only the type inferred from the default value).

如果未提供optional参数,它将使用类型为voidoptional实例化.这是不传递某些东西的一种方式.从技术上讲,这与检查是否提供了默认值并不相同,但是我认为像test(optional=_void)这样的呼叫站点在传达optional的值应被忽略(因为它是void)方面相当清楚.

If no optional argument is provided, it will instantiate with optional having type void. Which makes sense as a way to not pass something. Technically it's not the same as checking if the default value was provided, but I think a call site like test(optional=_void) is reasonably clear at communicating that the value of optional should be ignored (since it's void).

反正这里是代码:

proc test( optional:?t=_void ) {
  writeln("in test");
  writeln("  optional is ", optional);
  if optional.type == void then
    writeln("  note: default was used for optional");
}

test();
test([1, 2, 3]);

这篇关于没有默认值的可选函数参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆