2011-01-13 7 views
21

私はなぜこの質問をするのか説明します。私は最近、Lift 2.2のソースコードを読んでいます。 前にリフトのソースコードを読んだことがあって良かったです。なぜ、人々がScalaの別のオブジェクトの中にクラス、特性、オブジェクトを定義するのですか?

リフトでは、内部クラスと内部特性を定義することが非常に頻繁に使用されることがわかりました。

オブジェクトMenuには、2つの内部特性と4つの内部クラスがあります。オブジェクトLocには、18の内部クラス、5つの内部特性、7つの内部オブジェクトがあります。

このようなコードがたくさんあります。私はなぜ著者がこのように書くのか知りたい。それは著者の 個人的な好みや 言語機能の強力な使用だから

  • ですか?
  • この種のトレードオフはありますか? の使用状況はありますか?

答えて

18

2.8より前では、パッケージとオブジェクトのどちらかを選択する必要がありました。パッケージの問題は、独自のメソッドやvalを含むことができないことです。だからあなたはそれらをすべて別のオブジェクトの中に入れなければなりません。お守り:

object Encrypt { 
    private val magicConstant = 0x12345678 
    def encryptInt(i: Int) = i^magicConstant 
    class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] { 
    def hasNext = ii.hasNext 
    def next = encryptInt(ii.next) 
    } 
} 

import Encrypt._できるとクラスEncryptIteratorと同様の方法encryptIntへのアクセスを得ます。ハンディ!これとは対照的に

package encrypt { 
    object Encrypt { 
    private[encrypt] val magicConstant = 0x12345678 
    def encryptInt(i: Int) = i^magicConstant 
    } 
    class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] { 
    def hasNext = ii.hasNext 
    def next = Encrypt.encryptInt(ii.next) 
    } 
} 

それは巨大違いはありませんが、それは、ユーザーのインポートencrypt._encrypt.Encrypt._または両方が、何度もEncrypt.encryptIntを書いて維持する必要があります。最初のパターンのように、代わりにオブジェクトを使用するのはなぜですか?ネストされたクラスは実際にはJava内部クラスではなく、JVMが知っている限り普通のクラスですが、入れ子になっているという派手な名前が付いています)

In 2。8、あなたはあなたのケーキを持って、それも食べることができます:パッケージオブジェクトを呼び出すと、コンパイラはあなたのコードを書き直すので実際にはフードの下の2番目の例のように見えます(Encryptは実際にはpackageと呼ばれます)名前空間に関して最初の例のように動作します。余分なインポートを必要とせずに、valとdefがすぐそこにあります。

したがって、2.8より前に開始されたプロジェクトでは、多くのものをパッケージのように囲むためにオブジェクトを使用することがよくあります。ポスト2.8、主な動機の1つが削除されました。 (ただし、オブジェクトを使用しても傷つくことはありませんが、パフォーマンスやその他のものに悪影響を与えるよりも、概念的に誤解を招く可能性があります)。

そのようなことを例や冗談以外の方法で暗号化してください!)

+0

オブジェクトのネストされたクラスは、Javaの静的内部クラスとまったく同じですか?コンパニオンオブジェクトに100の内部クラスまたは100の内部オブジェクトを置くと、コンパイラはそれらをどのように扱いますか?パフォーマンスのペナルティはありませんか? – Sawyer

+1

クラスまたはオブジェクト 'Foo'内のネストされたクラス' Bar'は、内部クラスではなく、 'Foo $ Bar'という名前の_outer_クラスとして実装され、実際にその親クラスを使用する必要がある場合にのみ、親を指し示す(sort-of-hidden)フィールド。 JVMではなくコンパイラがこれを適切に使用するように強制します。オブジェクトの場合は、そのフィールドが1つしかないので、そのフィールドの格納に気をつける必要はありません。 –

3

どちらでも構いません。とりわけ、内部クラス/形質のインスタンスは、その親の変数にアクセスできます。内部クラスは、外部インスタンスのインスタンスである親インスタンスで作成する必要があります。

場合によっては、objectの例のように、密接に関連するものをグループ化するだけの方法です。特性LocParamは封印されていることに注意してください。つまり、すべてのサブクラスは同じコンパイル単位/ファイル内になければなりません。

+0

オブジェクトを使用して関連するものをグループ化すると、気分が良くなりません。パッケージの用途だと思います。 – Sawyer

+0

@Zwcat:あなたが言うことには多くの真実があります。しかし、便宜上、同じディレクトリ内の非常に多くのファイルではなく、これらの小さなものすべてを1つのファイルにまとめるのは簡単ではありません。 sealedキーワードを使用すると、それらを同じファイルに配置し、それを含むオブジェクトにラップする必要があります。 – sblundy

2

sblundyはまともな答えがあります。追加することの1つは、完全に別のオブジェクトを作成することなくパッケージネームスペース内で同様のものをグループ化できるようにするパッケージオブジェクトがScala 2.8のみであることです。そのため、リフトモジュールの提案を単純なオブジェクトの代わりにパッケージオブジェクトを使用するように更新します。

関連する問題