10

Scala コンストラクターで名前付き引数を使用し、後でコンストラクター インターフェイスを壊したり、コードを非常に醜くしたりすることなく、getter と setter をオーバーライドすることは可能ですか?

次のスカラ コードを見てください。

class Person( var FirstName: String, var LastName: String )

素敵できれい。これにより、次のように使用できる person という単純なクラスが作成されます。

val john = new Person( FirstName="John", LastName="Doe" )
john.FirstName = "Joe"
println( john.FirstName )

後で、FirstName セッターに検証を追加することにしました。そのため、新しいプライベート ローカル変数を作成し、ゲッター メソッドとセッター メソッドをオーバーライドします。

class Person( var _FirstName: String, var _LastName: String ) {

    def FirstName = _FirstName  
    def FirstName_= (value:String) = _FirstName = value

}

まだある程度きれいですが、これを行うには、コンストラクターの引数名を変更する必要があり、外部インターフェイスが壊れます。

私が思いついたこの問題の最初の解決策は

class Person {
    var _FirstName:String = null 
    var LastName:String  = null

    def FirstName = _FirstName  
    def FirstName_= (value:String) = _FirstName = value

    def this( FirstName: String, LastName: String ){
        this()
        this._FirstName = FirstName
        this.LastName = LastName 
    }

}

これはいくぶん醜くエレガントではなく、私が最初に scala を使用していた理由のほとんどを取り除いてしまいます。

これを行うより良い方法はありますか?

tl;drコードを醜くしたり、パブリックインターフェイスを変更したりせずに、デフォルトのコンストラクターで定義されたメンバーのゲッター/セッターをオーバーライドする方法は?

4

3 に答える 3

10

コンパニオン オブジェクトの使用を検討しましたか?

class Person private (f: String, l: String ) {
   var FirstName = f
   var LastName = l
}

object Person {
   def apply(FirstName:String, LastName:String) = 
       new Person(FirstName, LastName) 
}
于 2011-02-21T15:07:45.243 に答える
5

暗黙的な変換を使用して引数を作成していない場合は、次のようにすることができます。

def validateName(s: String) = {
  if (s.length>0 && s(0).isUpper) s
  else throw new IllegalArgumentException(s+" is not a name!")
}

object Example {
  private[Example] class ValidatedName(val s: String) { }
  class Person(var firstName: ValidatedName, var lastName: String) { }
  implicit def string2valid(s: String) = new ValidatedName(validateName(s))
  implicit def valid2string(v: ValidatedName) = v.s
}

scala> new Example.Person("Joe","Schmoe")
res17: Example.Person = Example$Person@51887dd5

scala> new Example.Person("ee","cummings")
java.lang.IllegalArgumentException: ee is not a name!

バイナリ互換ではありませんが、ソース互換です (名前がまだ暗黙の変換に依存していない場合)。

もう 1 つの少し長い可能性は、ステルスの祖先を作成することです。

class CheckedPerson(private var first: String, var lastName: String) {
  def firstName = first
  def firstName_=(s: String) { first = validateName(s) }
}
class Person(firstName: String, lastName: String) extends
  CheckedPerson(validateName(firstName),lastName) { }

バイナリの互換性についてはわかりませんが、ソースの互換性は確実に得られます。

于 2011-02-21T16:23:08.740 に答える
4

いいえ、現在それを行う方法はありません。現在、研究の焦点では​​ありません。

これは、私がこの言語に対して抱いている大きな不満の 1 つです。コンストラクターの引数と自己定義の getter/setter メソッドを組み合わせる賢明な方法はありません。

提供される機能に満足できない場合class Person( var FirstName: String, var LastName: String )、それは基本的に「Java の冗長性に戻る」ことを意味します。

于 2011-02-21T13:51:09.213 に答える