1

既存のJavaクラスpkg.Testがある場合、

package pkg;
public class Test {
  public int v;
  public Test(int v) { this.v = v; }
}

Scalaコンパニオンオブジェクトを定義してエクストラクタを作成しようとしています

package pkg
object Test{
  def unapply(t : Test) : Option[Int] = Some(t.v)
}

「テストはすでにオブジェクトテストとして定義されています」というエラーが生成されます。ただし、新しいパッケージでjavaクラスの同義語を作成すると、すべてが機能するようです。

package pkg
package object matchers {
  type Test = pkg.Test
}

新しいパッケージで対応するオブジェクトを定義します

package pkg.matchers
object Test {
  def unapply(t : Test) : Option[Int] = Some(t.v)
}

これで、パターンと元のクラスのすべてのメンバーの両方が新しいパッケージから利用可能になります

import pkg.matchers._
object main {
  def main(args : Array[String]) {
    val t = new Test(1)
    t match {case Test(v) => println(v)}
    println(t.v)
  }
}

型の同義語を追加すると、これが機能するのは奇妙に思えます。新しいパッケージを使用する必要がある以外に、この方法でパターンマッチングを追加することに問題はありますか?エクストラクタを元のパッケージで利用できるようにする方法はありますか?

4

1 に答える 1

4

これは、Java ライブラリと対話する場合、Scala は Java の静的メソッドを Scala のシングルトン オブジェクトにマップする方法を必要とするためです。

たとえば、次の Java クラスがあるとします。

package pkg;

class Test {
  public static void printHello() {
    System.out.println("Hello");
  }
}

printHelloScala でどのように呼び出すことができますか? 次のようになります。

import pkg.Test
Test.printHello()

ご覧のとおり、構文は でメソッドを呼び出すのとまったく同じobject Testです。この観点から、シングルトンはすでに定義されており、同じ FQN で を 2 回Test定義することはできません。object

pkg.matchers.Testそのため、と競合しないように定義する必要がありますpkg.Test

そして、Scala のコンパイラは、それがキーワードpkg.matchers.Testを使用して構築できなかったシングルトンであることを理解するほどスマートです。これが、コード例で同時に使用できる理由です。newnew Test(1)pkg.Testpkg.matchers.Test

実際、まったく必要ありませんtype Test = pkg.Test。以下は正常に機能しています。

package pkg

package matchers {
  object Test {
    def unapply(t : Test) : Option[Int] = Some(t.v)
  }
}

object main {

  import pkg.matchers._

  def main(args : Array[String]) {

    val t = new Test(1)
    t match {case Test(v) => println(v)}
    println(t.v)
  }
}

アップデート

Extractor はコンパニオン オブジェクトである必要はありません。つまり、対応するクラスは必要ありません。withメソッドはエクストラクタとして機能しますobjectunapply

object StringLength {
  def unapply(x: String): Option[Int] = Some(x.length)
}

object Main {

  def main(args: Array[String]) {

    "Hello World" match {
      case StringLength(x) => println("length:" + x)
    }
  }
}

したがって、メイン メソッドが にないpkg場合は、次の選択肢があります。

  1. エクストラクタの名前を別の名前に変更して、コンパイラがエクストラクタを使用していることを認識できるようにします。

  2. FQN を使用すると、コンパイラpkg.matchers.Testpkg.Test.

    package pkg.matchers {
    
      import pkg._
    
      object Test { 
        def unapply(t : Test) : Option[Int] = Some(t.v)
      } 
    }
    
    object Main {
    
      def main(args: Array[String]) {
    
        import pkg.Test
    
        val t = new Test(1)
        t match {case pkg.matchers.Test(v) => println(v)}
        println(t.v)
    
      }
    
    }
    
  3. 構文と競合しないように、pkg.Test別の名前に名前を変更します。importpkg.matchers.Test

    object Main {
    
      def main(args: Array[String]) {
    
        import pkg.{Test => JTest}
        import pkg.matchers.Test
    
        val t = new JTest(1)
        t match {case Test(v) => println(v)}
        println(t.v)
    
      }
    }
    
  4. pkgimport 特にを使用して、からすべてをインポートするだけpkg.matcher.Testです。

      def main(args: Array[String]) {
    
        import pkg._
        import pkg.matchers.Test
    
        val t = new Test(1)
        t match {case Test(v) => println(v)}
        println(t.v)
    
      }
    
于 2013-03-21T01:57:47.463 に答える