「to」と「as」のメソッド名プレフィックスの違いは何ですか?[閉まっている]


78

「to」「as」メソッド名のプレフィックスの違いは何ですか

  • toList()、
  • asList()、
  • 等...

メソッドを設計するときにいつ使用するか?

回答:


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
それは説明的な名前を選択することの一部であり、たとえこの特定の区別がコーディング標準で成文化されていなくても、それに違反すると最小の驚きの原則が破られます。

11
私はそれを本能的に、「to」を「change to」、「as」を「treat as」として考えると説明します。前者は物事を変えるための仕事を意味し、後者はあなたがそれを扱う方法の違いにすぎないことを意味します。
ラッティ

6
何かを意味する場合、これを意味するはずです。しかし、多くの場合、それは何の意味も持たないことをお勧めします。そのため、ランダムなサードパーティコードでは(ドキュメントで何かを見ることなく)それに依存しません。ただし、コードベースで採用するのは良い習慣です。
ベン

4
この答えはC ++でも正確です。たとえばstd::to_string(x)、新しい文字列オブジェクトをstd::as_const(x)作成しますが、既存のオブジェクトの参照(ビュー)を作成します。
-Quuxplusone

13

正直なところ、それは単に名前の不一致であるかもしれません。Smalltalkの中に標準ライブラリのオブジェクトを見れば、例えば、「別の型で返す簡単な表現」「複雑な変換」またはを行うすべてのメソッドは、接頭辞が付きますasのように、asStringasFloatasSeconds、、と何かに何かを変換するための標準的な方法as: aClass

ルビーでは、本方法の同じ種類で接頭辞to_のように、to_sto_ato_h、短いためstringarrayおよびhashそれぞれ。

どちらの標準ライブラリも異なる種類の変換を区別していないようです。おそらくそれは実装の詳細と見なされるべきだからです。

ただし、Javaでは多くの混乱が見られます。あなたが述べたように、ありますtoStringasListように、と。これらは単なる命名の不一致だと思います。なぜなら、各プレフィックスに異なる意味を定義しようとすると、常に標準ライブラリのどこかに反例が見つかるからです。

いずれにしても、重要なことは、あなたとあなたのチームが1つのプレフィックスを選択し、コード全体で一貫して使用することです。一貫性が鍵であるため、人々はあなたがしなければならなかったように不思議に思われることはありません。


1
私は信じていません。チーム全体で1つのスタイルを選択するのではなく、モジュール内の類似したケースで一貫して1つのスタイルを選択します。
ダニエルハリー

12
JavaではtoString、オブジェクトから完全に切り離された新しい文字列を作成します(不変性のため、他の方法はありません)。たとえば、forについてCollection#toArrayは同じですがArrays#asList、配列のビューを返しますが、これは双方向に接続されています(配列を変更するとリストが変更され、逆も同様です)。そのため、例外はあるかもしれませんが、かなり一貫しています。1つのプレフィックスを選択するのは間違っています。があった場合Arrays#toList、新しい基になる配列で新しいリストを作成することを期待しています。
-maaartinus

Smalltalkはそこで間違いを犯しただけだと思います。彼らは慣習を理解していませんでした。これは非常に抽象的であり、特に影響を与えるものではないため、理解すること(さらには通知することさえ)が難しい規則です。この質問をするという行為でさえ、ある程度の洞察が必要です。
usr

3
@usr Smalltalkのは、それが大会になる前に設計されている可能性があります
Bergi

6

すでに受け入れられている答えがありますが、質問にはjavaのタグが付けられていますが、C ++に焦点を当てているようです。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が古いパラダイムの人々にはより馴染みがあると考えているかもしれません。おそらく、これが仮想メソッドAsStringではなく仮想メソッドToString()を取得した理由です。


3
どうtoString()

参りました。AsStringの方が適切だと思います。いくつかの追加の考えを持たない、私の答えを更新します。
マーティンマート

この答えがC#の慣習に本当に合致するとは思わない。例えば。ToList()とAsEnumerable()は両方とも複雑なオブジェクトを返します。違いは、ToList()は常に新しいオブジェクトを返し、AsEnumerable()は元のオブジェクトのビューまたはアダプターを返すことです。
ジャックB

@JaquesBさまざまなアイデアがあちこちで適用されているようです。DelphiのTFieldオブジェクトには、データベースフィールドをカプセル化するAsIntegerプロパティとAsStringプロパティがあります。私はこれに偏っていたかもしれません。しかし、この場合も、C#やDelphiではなく、Javaで質問にタグが付けられます。
マーティンマート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.