18

私は「ScalafortheImpatient」の演習5.7を行っています。ここでは、コンストラクターでname:Stringを取り、空白で分割された名前から2つのプロパティfirstNamelastNameを持つクラスPersonを作成する必要があります。私の最初の裁判は:

class Person(name:String) {
  private val nameParts = name.split(" ")

  val firstName = nameParts(0)
  val lastName = nameParts(1)
}

問題は、namePartsが、実際にはコンストラクターのローカル環境内にのみ存在する必要があるのに、クラス内で常に表示されるプライベートフィールドとして残ることです。私が欲しいものに相当するJavaは次のようになります。

 class Person{
    private final String firstName;
    private final String lastName;

    Person(String name){
        final String[] nameParts = name.split(" ");
        firstName = nameParts[0];
        lastName = nameParts[1];
    }
 }

ここで、namePartsは、私が目指しているコンストラクターを使用してのみ存在します。これをScalaでどのように行うことができるかについてのヒントはありますか?

注:私はより「Scalesque」な方法を見つけることになりました:

class Person(name:String) {
    val firstName::lastName::_ = name.split(" ").toList 
}

しかし、私はまだ私の質問に対する答えを得たいと思います。

4

5 に答える 5

14

を回避する方法がありprivate valます。の抽出を使用するだけですArray

class Person(name: String) {
  val Array(first, last) = name.split(" ")
}

編集:

コンパニオンのファクトリメソッドと、最初と最後をパラメーターとして受け取るデフォルトのコンストラクターを使用して、実行したいことを実現できます。

class Person(val first: String, val last: String)

object Person {
  def apply(name: String) = {
    val splitted = name.split(" ")
    new Person(splitted(0), splitted(1))
  }
}

scala> Person("Foo Bar")
res6: Person = Person@37e79b10

scala> res6.first 
res7: String = Foo

scala> res6.last
res8: String = Bar

しかし、この単純なケースでは、最初の提案をお勧めします。

リンクの例も機能しますが、最初の例と同じです。Afaikコンストラクターで一時変数を作成する方法はありません。

于 2012-04-15T13:56:25.983 に答える
4

私が考えていたのは単純なことでした

class Person(n: String) {
  val firstName = n.split(" ")(0)
  val lastName = n.split(" ")(1)
}

一般的なコードを除外したい場合は、配列を使用したdrexinの答えは非常に優れています。ただし、読者が第5章では得られなかった知識が必要です。ただし、タプルを使用したvarは第4章で説明されているため、次のことが可能です。

class Person(n: String) {
  val (firstName, lastName) = { val ns = n.split(" "); (ns(0), ns(1)) }
}
于 2012-06-12T15:53:51.123 に答える
3

@drexinの答えへの単なる追加。この例class Person(name:String)では、コンストラクターパラメーターは引き続きとして保存されprivate[this] val name: String、クラス内でアクセスできます。次に例を示します。

class Person(name:String) {
  def tellMeYourName = name
}

これを本当に避けたい場合は、コンパニオンオブジェクトを作成し、プライマリコンストラクターをプライベートにすることができます。

class Person private (val fName: String, val lName: String)

object Person {
  def apply(name: String) = {
    val Array(fName, lName) = name split " "
    new Person(fName, lName)
  }
}

Person別の方法は、コンパニオンオブジェクトを使用してトレイトを作成することです。

trait Person {
  val lName: String
  val fName: String
}
object Person {
  def apply(name: String) = new Person {
    val Array(lName, fName) = name split " "
  }
}
于 2012-04-15T14:52:31.050 に答える
2

Extractorの定義や、コンパニオンオブジェクトメソッドの必要性を回避するアプローチは次のとおりです。

class Person(name: String) {    
  val (firstName, lastName) = {
    val nameParts = name.split(" ")
    (nameParts(0), nameParts(1))
  } 
}
object Example {
  println(new Person("John Doe").firstName)
}

で囲まれたscala式{..}は、内の最後の部分式の値を持ちます

于 2015-10-12T12:16:26.307 に答える
1

これを行う一般的なscalaの方法は、コンパニオンオブジェクトを使用することです(以前の回答で説明されています)。

ただし、これが問題になる場合があります(たとえば、クラスを継承し、内部ロジックを知らずに関連するコンストラクターを呼び出したい場合、またはリフレクトを介してクラスをインスタンス化したい場合)。

クラス内で直接行うかどうかを知る唯一の方法は、少し複雑です。

class Person(name: String, x: Seq[String]) {
  val firstName = x(0)
  val lastName = x(1)

  def this(name: String) {
    this(name, name.split(" "))
  }
}

x(名前と同じ)にはvarまたはvalがないため、private[this]valに変換されるという考え方です。

オプティマイザーは、コンストラクターの外部では使用されないため、通常の関数パラメーターとして使用でき、保存されないことを認識しています。これを可能にするのは内部呼び出しです。

javap -private Person.classの結果:

public class com.rsa.nw_spark.Person {
  private final java.lang.String firstName;
  private final java.lang.String lastName;
  public java.lang.String firstName();
  public java.lang.String lastName();
  public com.rsa.nw_spark.Person(java.lang.String, scala.collection.Seq<java.lang.String>);
  public com.rsa.nw_spark.Person(java.lang.String);
}

この解決策は、次のように何度か言及されています。

class Person(name: String) {    
  val (firstName, lastName) = {
    val nameParts = name.split(" ")
    (nameParts(0), nameParts(1))
  } 
}

実際には機能しません。保存される一時タプルを作成します。javap -private Person.classの結果:

public class com.rsa.nw_spark.Person {
  private final scala.Tuple2 x$1;
  private final java.lang.String firstName;
  private final java.lang.String lastName;
  public java.lang.String firstName();
  public java.lang.String lastName();
  public com.rsa.nw_spark.Person(java.lang.String);
}
于 2016-11-24T12:31:32.847 に答える