序列和序列化参数

   |       Ceylon

我在思考如何将一个序列传递给Ceylon中的序列化参数(在Java术语中为varargs参数)。考虑

void print(Object... objects) { ... }
String[] words = {"hello", "world"};
print(words);   //what does this do?

第二行是否意味着我们传递了一个单独的Sequenceprint(),或者两个String字符串?Java在这种情况下表现得很奇怪

//Java:
print(new String[]{"hello", "world"}); //passes two Strings with a compiler warning asking for an explicit cast to Object[]
print(new Object[]{"hello", "world"}); //passes two Objects with no compiler warning
print(new String[]{"hello", "world"}, new String[]{"hello", "world"}); //passes two String[] arrays as varargs!

呃!

当存在这样的泛型方法时,事情变得更加复杂

T? first<T>(T... objects) { ... }
String[] words = {"hello", "world"};
first(words);    //what type should be inferred for T?

这真会破坏我美丽的干净类型参数推断算法!这也是为什么现在出现这个问题 - 这是一个只有在实现类型分析器中的泛型类型参数推断时才会注意到的问题。

因此,我认为我们需要明确指定当你向序列化参数传递一系列值时你到底想表达什么。我对此有几种想法。

解决方案1

第一个解决方案,某种程度上受到了groovy的启发,将在位置参数方法调用协议中引入特殊语法。

String[] words = {"hello", "world"};

print(words);      //pass a single String[]
print(words...);   //pass two Strings

String[]? words2 = first(words);   //infers T = String[];
String? word = first(words...);    //infers T = String

我认为这读起来相当自然。缺点是它是一种特殊用途的标点符号,需要在规范中特别解释。

解决方案2

第二个解决方案是引入一个特殊类型(一个子类型)来表示一系列序列化参数的包。称之为序列SequencedArguments。然后,通过一个包装的辅助方法spread(),语法将类似于序列这稍微有点冗长,但合理。这也使得编写规范更容易。。然后,通过一个包装解决方案3

String[] words = {"hello", "world"};

print(words);           //compiler automatically produces a SequencedArguments<String[]>
print(spread(words)));  //explicitly pass a SequencedArguments<String>

String[]? words2 = first(spread(words));    //infers T = String[];
String? word = first(spread(words));        //infers T = String

解决方案1和2可以非常优雅地结合。我们可以定义

T...

表示

  • SequencedArguments对于任何类型Te...
  • 表示对于任何类型SequencedArguments(e)对于任何表达式e

所以SequencedArguments只是一个类型名称缩写,类似于T[]T?表示它只是一个运算符表达式。我们的语法与解决方案1完全相同,但具有解决方案2的语义。

我认为这是可行的,并且非常符合语言的精神。另一方面,如果SequencedArguments只是一个普通的类型声明,我不知道我们如何确保序列化参数必须是参数列表中的最后一个参数。我有点喜欢这是一个错误

void print(Object... objects, OutputStream stream) { ... } //compile error?

你的看法呢?print(words...)对于你们来说读起来怎么样,或者它感觉是任意的吗?

附言:

不要将这个与将操作应用于功能语言和动态语言中的参数元组的思想混淆。这表面上很相似,但并不完全相同。

更新:

一种合理的语法变化,可能读起来更好,可以使用所有作为一个关键字

void print(Object all objects) { ... }
print(words);       //pass a single String[]
print(all words);   //pass two Strings

如果我不是那么讨厌将非常有用的单词“所有”变成关键字,我可能会接受这个。


返回顶部