“ to”和“ as”方法名称前缀之间有什么区别?[关闭]


78

“ to”“ as”方法名称前缀(例如)之间有什么区别

  • toList(),
  • asList(),
  • 等等...

设计方法何时使用?

Answers:


120

一个toXYZ()函数应该进行转换,并返回一个新的独立对象(尽管不变性允许优化,java.lang.String.toString()只是返回该对象)。
举个例子,在C ++中,我们有std::bitset::to_ulong()容易出错的软件,还有大量的软件to_string(),它们都(或多或少)进行复杂的转换并分配内存。

asXYZ()另一方面,期望一个函数返回源的(可能不同)视图,从而完成最少的工作。
例如,在C ++中,我们std::as_const()仅返回一个常量引用,而涉及更多的std::forward_as_tuple对象也通过引用引用其参数。


19
事实证明,这存在一些先例。通常,As [something]类似于强制类型转换,而To [something]则从现有对象构造一个新对象(不同类型)。对于ToList,它将是O(n),几乎可以肯定比“ As”贵。参见 stackoverflow.com/questions/17968469/…–
罗伯特·哈维

5
这是选择描述性名称的一部分,即使此特殊区分未在编码标准中进行编码,但违反此规定则会破坏最小惊讶原则
Deduplicator

11
我本能地将其描述为“至”为“改变为”,而“ as”为“处理为”。前者意味着改变事物的工作,而后者则意味着改变事物的方式。
Latty

6
如果这意味着某事,那应该意味着这。我建议尽管它通常通常并不意味着什么,所以我不会在随机的第三方代码中依赖它(在文档中看不到任何东西)。不过,采用代码库将是一个很好的约定。

4
这个答案在C ++中也是正确的:例如,std::to_string(x)创建一个新的字符串对象,但std::as_const(x)创建现有对象的引用(视图)。
Quuxplusone

13

老实说,它可能只是命名不一致。如果看一下在Smalltalk标准库对象,例如,那些“复杂的转换”或“其他类型的返回简单表示”所有的方法都带有前缀as,如asStringasFloatasSeconds,和任何东西转换成任何东西的标准方法,as: aClass

在Ruby中,相同种方法的前缀为to_,如在to_sto_ato_h,简称stringarrayhash分别。

两种标准库似乎都无法区分不同类型的转换,可能是因为应该将其视为实现细节。

但是,在Java中,我们看到了很多混淆。至于你提到的有toStringasList等。我相信这些只是命名不一致,因为如果您尝试为每个前缀定义不同的含义,那么您总是会在标准库的其他地方找到反例。

因此,无论如何,我要说的重要一点是,对于您和您的团队来说,选择一个前缀并在整个代码中一致地使用它。一致性是关键,因此人们不必像以前那样好奇。


1
我不相信:为整个团队选择一种样式,而是始终如一地为模块中的类似案例选择一种样式。
丹尼尔·哈里(DanielHári)

12
在Java中,toString创建一个与对象完全断开连接的新字符串(由于不变性,没有其他方法)。同样,例如for Collection#toArray,同时Arrays#asList返回数组的视图,该视图是双向连接的(更改数组会更改列表,反之亦然)。因此它是相当一致的,尽管可能会有例外。选择一个前缀将是错误的。如果存在Arrays#toList,那么我希望它会创建一个具有新基础数组的新列表。
maaartinus

我认为Smalltalk只是在这里犯了一个错误,他们不了解约定。这是一个很难理解(甚至引起注意)的约定,因为它是如此抽象并且影响不大。甚至问这个问题的行为也需要一些洞察力。
usr

3
@usr Smalltalk可能是在成为惯例之前进行设计的
Bergi'7

6

虽然已经有一个公认的答案,但它似乎集中在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();
      }
    }
  }

1

我注意到的差异(现在只是通过思考)是

  • 通常转换为其他引用类型(有些复杂的对象)
  • 通常返回简单的值类型

因此,我们看到了AsInteger和AsString以及ToArray和ToStringList。

暗示转换是有意义的(这是运动,过程)。隐含一种表示形式,一种表达原始对象的方式。

另一种查找方式:

  • To是一项操作,因此您可以将其用于方法。
  • 由于是一种简单的表示形式,因此可以将其用于属性。

然后是“先有艺术”(或遗产)要处理。在语言从头开始完全面向对象之前,您将拥有StrToInt()和IntToStr()之类的库函数。他们执行了转换,是操作,因此将它们称为SomethingToSomethingelse()很有意义。毕竟,To比As更活跃。我在这里特别考虑Delphi。

当C#的目标是一直朝着OO方向发展时,在现在的整数对象上有一个方法可以将整数转换为字符串是有意义的。尽管我们还有一个Convert类,但转换为字符串非常普遍,以至于它已成为对象的虚拟方法。设计人员可能已经发现,旧范式的人们会更熟悉ToString,这也许就是为什么我们有了虚拟方法ToString()而不是虚拟属性AsString的原因。


3
toString()
Deduplicator

你让我在那里。我认为AsString更合适。我还有其他想法,我将更新答案。
马丁·马特

我认为这个答案真的不符合C#中的约定。例如。ToList()和AsEnumerable()都返回复杂的对象,不同之处在于ToList()始终返回新对象,而AsEnumerable()返回原始对象的视图或适配器。
JacquesB

@JaquesB显然在这里和那里已经应用了不同的想法。Delphi在TField对象(封装数据库字段)上具有AsInteger和AsString属性。我可能对此有偏见。但是话又说回来,这个问题是用Java而不是C#或Delphi标记的。
马丁·马特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.