サーチ…


構文

  • class MyClass{} // curly braces are optional here as class body is empty
  • class MyClassWithMethod {def method: MyClass = ???}
  • new MyClass() //Instantiate
  • object MyObject // Singleton object
  • class MyClassWithGenericParameters[V1, V2](vl: V1, i: Int, v2: V2)
  • class MyClassWithImplicitFieldCreation[V1](val v1: V1, val i: Int)
  • new MyClassWithGenericParameters(2.3, 4, 5)または異なるタイプのnew MyClassWithGenericParameters[Double, Any](2.3, 4, 5)
  • class MyClassWithProtectedConstructor protected[my.pack.age](s: String)

クラスインスタンスのインスタンス化

Scalaのクラスは、クラスインスタンスの「青写真」です。インスタンスには、そのクラスで定義されている状態と動作が含まれます。クラスを宣言するには:

class MyClass{}  // curly braces are optional here as class body is empty

newキーワードを使用してインスタンスをインスタンス化することができます。

var instance = new MyClass()

または:

var instance = new MyClass

Scalaでは、引数のないコンストラクタを持つクラスからオブジェクトを作成するためのカッコはオプションです。クラスコンストラクタが引数を取る場合:

class MyClass(arg : Int)       // Class definition
var instance = new MyClass(2)  // Instance instantiation
instance.arg                   // not allowed

ここでMyClassは、内部でのみ使用できるInt引数が1つ必要です。 argは、フィールドとして宣言されていない限り、 MyClass外部からアクセスすることはできません:

class MyClass(arg : Int){ 
    val prop = arg  // Class field declaration
} 

var obj = new MyClass(2)
obj.prop     // legal statement

あるいは、コンストラクタでpublicとして宣言することもできます。

class MyClass(val arg : Int)   // Class definition with arg declared public
var instance = new MyClass(2)  // Instance instantiation
instance.arg                   //arg is now visible to clients

パラメータなしでクラスをインスタンス化する:{} vs()

コンストラクタ引数を持たないMyClassクラスがあるとしましょう:

class MyClass

Scalaでは、以下の構文を使用してインスタンス化できます。

val obj = new MyClass()

あるいは単に次のように書くことができます:

val obj = new MyClass

しかし、注意を払わなければ、オプションのかっこで予期しない動作が生じることがあります。別のスレッドで実行するタスクを作成したいとします。以下はサンプルコードです:

val newThread = new Thread { new Runnable {
        override def run(): Unit = {
            // perform task
            println("Performing task.")
        }
      }
    }

newThread.start   // prints no output

このサンプルコードを実行するとPerforming task.が印刷されると考えられPerforming task.しかし、驚いたことに、それは何も印刷されません。ここで何が起こっているか見てみましょう。より詳しくお知りになりたい場合は、 new Thread直後に中括弧{}を使用しています。 Threadを拡張するアノニマスクラスを作成しました:

val newThread = new Thread {
  //creating anonymous class extending Thread
}

そして、このアノニマスクラスの本体で、私たちのタスクを定義しました(もう一度、 Runnableインターフェースを実装するアノニマスクラスを作成します)。だから我々は、我々が使用することを考えているかもしれないpublic Thread(Runnable target)コンストラクタを実際に(別売無視して()我々が使用public Thread()の本体で定義されて何もコンストラクタをrun()メソッド。問題を解決するには、中括弧の代わりにかっこを使用する必要があります。

val newThread = new Thread ( new Runnable {
        override def run(): Unit = {
            // perform task
            println("Performing task.")
        }
      }
    )

言い換えれば、ここで{}()交換できません。

シングルトン&コンパニオンオブジェクト

シングルトンオブジェクト

Scalaは静的メンバーをサポートしますが、Javaと同じ方法ではありません。 Scalaはこれに代わるSingleton Objectsを提供します。シングルトンオブジェクトは、 newキーワードを使用してインスタンス化することはできない点を除いて、通常のクラスに似ています。以下は、シングルトンクラスのサンプルです。

object Factorial {
    private val cache = Map[Int, Int]()
    def getCache = cache
}

「class」や「trait」ではなくsingletonオブジェクトを定義するためにobjectキーワードを使用していobject 。シングルトンオブジェクトはインスタンス化できないため、パラメータを持つことはできません。シングルトンオブジェクトへのアクセスは次のようになります。

Factorial.getCache() //returns the cache

これは、Javaクラスの静的メソッドにアクセスするのとまったく同じように見えることに注意してください。

コンパニオンオブジェクト

Scalaでは、シングルトンオブジェクトは対応するクラスの名前を共有できます。このようなシナリオでは、シングルトンオブジェクトはコンパニオンオブジェクトと呼ばれます。たとえば、クラスFactorialが定義され、その下にコンパニオンオブジェクト( Factorialという名前)が定義されています。慣例により、コンパニオンオブジェクトはコンパニオンクラスと同じファイルに定義されます。

class Factorial(num : Int) {

  def fact(num : Int) : Int = if (num <= 1) 1 else (num * fact(num - 1))

  def calculate() : Int = {
    if (!Factorial.cache.contains(num)) {    // num does not exists in cache
      val output = fact(num) // calculate factorial
      Factorial.cache += (num -> output)     // add new value in cache
    }

    Factorial.cache(num)
  }
}

object Factorial {
  private val cache = scala.collection.mutable.Map[Int, Int]()
}

val factfive = new Factorial(5)
factfive.calculate  // Calculates the factorial of 5 and stores it
factfive.calculate  // uses cache this time
val factfiveagain = new Factorial(5)
factfiveagain.calculate  // Also uses cache

この例では、プライベートcacheを使用して、反復数の計算時間を節約するために階乗を格納しています。

ここでは、 object Factorialはコンパニオンオブジェクトであり、 class Factorialは対応するコンパニオンクラスです。コンパニオンオブジェクトとクラスは、お互いのprivateメンバーにアクセスできます。上記の例では、 Factorialクラスは、そのコンパニオンオブジェクトのプライベートcacheメンバーにアクセスしています。

クラスの新しいインスタンス化では、同じコンパニオンオブジェクトが引き続き使用されるため、そのオブジェクトのメンバー変数への変更は引き継がれます。

オブジェクト

クラスは青写真に似ていますが、オブジェクトは静的です(つまり、すでにインスタンス化されています)。

object Dog {
    def bark: String = "Raf"
}

Dog.bark() // yields "Raf"

彼らはしばしばクラスのコンパニオンとして使用され、あなたは次のように書くことができます:

class Dog(val name: String) {

}

object Dog {
    def apply(name: String): Dog = new Dog(name)
}

val dog = Dog("Barky") // Object
val dog = new Dog("Barky") // Class

インスタンスの型チェック

タイプチェックvariable.isInstanceOf[Type]

パターンマッチング (この形式ではあまり役に立ちません):

variable match {
  case _: Type => true
  case _ => false
}

isInstanceOfとパターンマッチングでは、配列を除いて、オブジェクトの型だけをチェックし、型パラメータを持たないジェネリックパラメータはチェックしません。

val list: List[Any] = List(1, 2, 3)             //> list  : List[Any] = List(1, 2, 3)

val upcasting = list.isInstanceOf[Seq[Int]]     //> upcasting  : Boolean = true

val shouldBeFalse = list.isInstanceOf[List[String]]
                                                //> shouldBeFalse  : Boolean = true

しかし

val chSeqArray: Array[CharSequence] = Array("a") //> chSeqArray  : Array[CharSequence] = Array(a)
val correctlyReified = chSeqArray.isInstanceOf[Array[String]]
                                              //> correctlyReified  : Boolean = false


val stringIsACharSequence: CharSequence = ""    //> stringIsACharSequence  : CharSequence = ""
  
val sArray = Array("a")                         //> sArray  : Array[String] = Array(a)
val correctlyReified = sArray.isInstanceOf[Array[String]]
                                                //> correctlyReified  : Boolean = true

//val arraysAreInvariantInScala: Array[CharSequence] = sArray
//Error: type mismatch;  found   : Array[String]  required: Array[CharSequence]
//Note: String <: CharSequence, but class Array is invariant in type T.
//You may wish to investigate a wildcard type such as `_ <: CharSequence`. (SLS 3.2.10)
//Workaround:
val arraysAreInvariantInScala: Array[_ <: CharSequence] = sArray
                                                //> arraysAreInvariantInScala  : Array[_ <: CharSequence] = Array(a)
  

val arraysAreCovariantOnJVM = sArray.isInstanceOf[Array[CharSequence]]
                                                //> arraysAreCovariantOnJVM  : Boolean = true

型キャストvariable.asInstanceOf[Type]

パターンマッチングでは

variable match {
  case _: Type => true
}

例:

  val x = 3                                       //> x  : Int = 3
  x match {
    case _: Int => true//better: do something
    case _ => false
  }                                               //> res0: Boolean = true
  
  x match {
    case _: java.lang.Integer => true//better: do something
    case _ => false
  }                                               //> res1: Boolean = true
  
  x.isInstanceOf[Int]                             //> res2: Boolean = true
  
  //x.isInstanceOf[java.lang.Integer]//fruitless type test: a value of type Int cannot also be a Integer
  
  trait Valuable { def value: Int}
  case class V(val value: Int) extends Valuable
  
  val y: Valuable = V(3)                          //> y  : Valuable = V(3)
  y.isInstanceOf[V]                               //> res3: Boolean = true
  y.asInstanceOf[V]                               //> res4: V = V(3)

備考:これはJVMの動作に関するもので、他のプラットフォーム(JS、ネイティブ)の型キャスト/チェックでは動作が異なる場合があります。

コンストラクタ

プライマリコンストラクタ

Scalaでは、プライマリコンストラクタはクラスの本体です。クラス名の後には、コンストラクタ引数であるパラメータリストが続きます。 (他の関数と同様に、空のパラメータリストは省略することができます)。

class Foo(x: Int, y: String) {
    val xy: String = y * x
    /* now xy is a public member of the class */
}

class Bar {
    ...
}

valキーワードでインスタンスメンバとしてマークされていない限り、インスタンスの構築パラメータはコンストラクタ本体の外部ではアクセスできません。

class Baz(val z: String) 
// Baz has no other members or methods, so the body may be omitted

val foo = new Foo(4, "ab")
val baz = new Baz("I am a baz")
foo.x // will not compile: x is not a member of Foo
foo.xy // returns "abababab": xy is a member of Foo
baz.z // returns "I am a baz": z is a member of Baz
val bar0 = new Bar
val bar1 = new Bar() // Constructor parentheses are optional here

オブジェクトのインスタンスがインスタンス化されるときに実行される操作は、クラスの本文に直接記述されます。

class DatabaseConnection
    (host: String, port: Int, username: String, password: String) {
    /* first connect to the DB, or throw an exception */
    private val driver = new AwesomeDB.Driver()
    driver.connect(host, port, username, password)
    def isConnected: Boolean = driver.isConnected
    ...
}

できるだけ副作用を少なくすることはコンストラクタに置くことをお勧めします。上記のコードの代わりに、消費者コードがIOのスケジューリングを担当するように、 connectdisconnect方法を検討する必要connectありdisconnect

補助コンストラクタ

クラスには、補助コンストラクタと呼ばれる追加のコンストラクタがあるかもしれません。これらはdef this(...) = eという形式のコンストラクタ定義で定義されdef this(...) = eここでeは別のコンストラクタを呼び出さなければなりません:

class Person(val fullName: String) {    
  def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}

// usage:
new Person("Grace Hopper").fullName // returns Grace Hopper
new Person("Grace", "Hopper").fullName // returns Grace Hopper

これは、各コンストラクタが異なる修飾子を持つことができることを意味します。

class Person private(val fullName: String) {    
  def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}

new Person("Ada Lovelace") // won't compile
new Person("Ada", "Lovelace") // compiles

このようにして、コンシューマコードがクラスをインスタンス化する方法を制御することができます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow