Answers:
一个toXYZ()
函数应该进行转换,并返回一个新的独立对象(尽管不变性允许优化,java.lang.String.toString()
只是返回该对象)。
举个例子,在C ++中,我们有std::bitset::to_ulong()
容易出错的软件,还有大量的软件to_string()
,它们都(或多或少)进行复杂的转换并分配内存。
asXYZ()
另一方面,期望一个函数返回源的(可能不同)视图,从而完成最少的工作。
例如,在C ++中,我们std::as_const()
仅返回一个常量引用,而涉及更多的std::forward_as_tuple
对象也通过引用引用其参数。
std::to_string(x)
创建一个新的字符串对象,但std::as_const(x)
创建现有对象的引用(视图)。
老实说,它可能只是命名不一致。如果看一下在Smalltalk标准库对象,例如,那些“复杂的转换”或“其他类型的返回简单表示”所有的方法都带有前缀as
,如asString
,asFloat
,asSeconds
,和任何东西转换成任何东西的标准方法,as: aClass
。
在Ruby中,相同种方法的前缀为to_
,如在to_s
,to_a
,to_h
,简称string
,array
和hash
分别。
两种标准库似乎都无法区分不同类型的转换,可能是因为应该将其视为实现细节。
但是,在Java中,我们看到了很多混淆。至于你提到的有toString
,asList
等。我相信这些只是命名不一致,因为如果您尝试为每个前缀定义不同的含义,那么您总是会在标准库的其他地方找到反例。
因此,无论如何,我要说的重要一点是,对于您和您的团队来说,选择一个前缀并在整个代码中一致地使用它。一致性是关键,因此人们不必像以前那样好奇。
toString
创建一个与对象完全断开连接的新字符串(由于不变性,没有其他方法)。同样,例如for Collection#toArray
,同时Arrays#asList
返回数组的视图,该视图是双向连接的(更改数组会更改列表,反之亦然)。因此它是相当一致的,尽管可能会有例外。选择一个前缀将是错误的。如果存在Arrays#toList
,那么我希望它会创建一个具有新基础数组的新列表。
虽然已经有一个公认的答案,但它似乎集中在C ++上,而问题是用java标记的。在Java中,想到的第一个例子是Arrays.asList,它本质上返回包装在列表中的数组视图。底层数组和列表仍然保持连接;对数组所做的更改将反映在列表中,反之亦然。但是,列表的toArray方法返回的数组独立于原始数组和列表:
String[] wordArray = {"one", "fine", "day"};
List<String> wordList = Arrays.asList(wordArray);
// changes to the array are visible in the list
System.out.println(wordList); // prints "[one, fine, day]"
wordArray[1] = "horrible";
System.out.println(wordList); // prints "[one, horrible, day]"
// changes to the list are visible in the array
wordList.set(1, "beautiful");
System.out.println(wordArray[1]); // prints "beautiful"
// but changes to the list or array don't affect the
// result from the list's toArray method.
String[] moreWords = wordList.toArray(new String[] {});
wordList.set(0, "the");
wordArray[1] = "best";
for (int i=0; i<3; i++) {
System.out.println(moreWords[i]); // prints "one", "beautiful", and "day"
}
综上所述,不能保证每个库开发人员都遵守此约定,因此您仍然需要检查文档以了解这是否是从未知代码中得到的行为。
我看过的另一个经常使用的...()方法是将类型转换为子类型。例如,如果您有一组枚举的子类型,那么最终可能会得到如下代码:
/**
* Every Node is either an ANode or a BNode.
*/
interface Node {
/**
* Returns this Node as an ANode.
*
* @return this node
*/
default ANode asANode() {
if (this instanceof ANode) {
return (ANode) this;
}
else {
throw new UnsupportedOperationException();
}
// Or, in Java8 style, perhaps:
// return Optional.of(this)
// .filter(ANode.class::isInstance)
// .map(ANode.class::cast)
// .orElseThrow(UnsupportedOperationException::new);
}
/**
* Returns this Node as a BNode.
*
* @return this node
*/
default BNode asBNode() {
if (this instanceof BNode) {
return (BNode) this;
}
else {
throw new UnsupportedOperationException();
}
}
}
我注意到的差异(现在只是通过思考)是
因此,我们看到了AsInteger和AsString以及ToArray和ToStringList。
暗示转换是有意义的(这是运动,过程)。隐含一种表示形式,一种表达原始对象的方式。
另一种查找方式:
然后是“先有艺术”(或遗产)要处理。在语言从头开始完全面向对象之前,您将拥有StrToInt()和IntToStr()之类的库函数。他们执行了转换,是操作,因此将它们称为SomethingToSomethingelse()很有意义。毕竟,To比As更活跃。我在这里特别考虑Delphi。
当C#的目标是一直朝着OO方向发展时,在现在的整数对象上有一个方法可以将整数转换为字符串是有意义的。尽管我们还有一个Convert类,但转换为字符串非常普遍,以至于它已成为对象的虚拟方法。设计人员可能已经发现,旧范式的人们会更熟悉ToString,这也许就是为什么我们有了虚拟方法ToString()而不是虚拟属性AsString的原因。
toString()
呢