9

純粋な Scala 環境では、ファクトリ メソッドを既存のオブジェクトに「追加」したい場合、次のようにできます。

object Test

object Extensions {

    object RichTest {
        def someFactory = new Test()
    }
    implicit def fromTest(t: Test.type) = RichTest

}

...

import Extensions._
val t = Test.someFactory

このような機能は、既存の Java クラスと組み合わせて使用​​する必要があります。私の具体的な例ではfromLocation、クラスにファクトリ メソッドを追加したいcom.google.android.maps.GeoPointと思います (そして、すべての Android 開発者は、これが役立つ理由を知っていると思います ;-) )。

ただし、次のようなことをしようとすると

implicit def fromGeoPoint(t: GeoPoint.type) = RichTest

エラーが表示されます

型の不一致; 見つかった: com.google.android.maps.GeoPoint.type (基になる型オブジェクト com.google.android.maps.GeoPoint を使用) 必須: AnyRef

したがって、上記のアプローチを実装する方法があるかどうか、またはaが必要なときにいつでも a を使用できるように、からの暗黙的な変換を Scala で推奨される方法でLocation提供するかどうか疑問に思います。GeoPointLocationGeoPoint


コメントで要求されているように、使用シナリオ:

// Callback you get from the GPS
override def onLocationChanged(l: Location) {
    // You want to put a marker on a map, hence a GeoPoint is required
    val gp: GeoPoint = GeoPoint.fromLocation(location)
    val item = new OverlayItem(gp, ...)
    ....
}

ただし、これは一般的な問題の具体例の 1 つにすぎないことに注意してください ;-)

4

6 に答える 6

2

Scala バージョン 2.9.1 では、Java クラスをファクトリ メソッドで拡張することはできません。

ただし、次の 3 つの代替ソリューションがあります。

  1. 必要な変更に対応するScala コンパイラ プラグインを作成し、Java クラスを拡張します。
  2. スタンドアロンのファクトリ メソッドを作成します。
  3. ファクトリ メソッドを完全に使用することを避け、暗黙的な変換を追加して、常に GeoPoint の代わりに Location オブジェクトを使用できるようにします。

個人的には、Location->GeoPointまたはその他の変換を頻繁に使用する場合、特に例外なく常に変換を実行でき、クラス インターフェイスが重複しないシナリオでは、3 番目のオプションを選択します。

implicit def geoPointFromLocation(l: Location):GeoPoint = new GeoPoint...

override def onLocationChanged(l: Location) {        
    val gp: GeoPoint = l  // let Scala compiler do the conversion for you
    val item = new OverlayItem(gp, ...)
    ....
    // or just pass the location to OverlayItem constructor directly
    val item2 = new OverlayItem(l, ...)
}
于 2012-03-08T15:16:29.047 に答える
2

素晴らしい質問です!残念ながら、それは不可能だと思います。Java では、クラスの静的部分を値として使用する方法がないため、Java クラスの静的メンバーの型が AnyRef を拡張する理由はありません。残念ながら、その Java オブジェクトを AnyRef に拡張するには、Java オブジェクトに AnyRef を拡張する必要がある暗黙の変換を使用します...

私は間違っていると証明されたいです!

更新: Java でこれを行うことはできません。ベスト プラクティスは、ファクトリ メソッドを追加する独自の静的クラスを作成することだと思います。たとえば、GuavaのListを考えてみましょう。

更新: Java と Scala の違いの完全な例 (Dario が説明したもの) を次に示します。

# vim Test.java
class Test {
  public static final int foo = 1;
  public final int bar = 2;
}

# javac Test.java
# ls

Test.class  Test.java

# javap Test

Compiled from "Test.java"
class Test {
  public static final int foo;
  public final int bar;
  Test();
}

比較すると、scala を使用した場合:

# vim Test.scala

object Test {
  val foo = 1
}

class Test {
  val bar = 2
}

# javac Test.scala
# ls

Test$.class  Test.class  Test.scala

# javap Test

public class Test implements scala.ScalaObject {
  public static final int foo();
  public int bar();
  public Test();
}

# javap Test$

Compiled from "Test.scala"
public final class Test$ implements scala.ScalaObject {
  public static final Test$ MODULE$;
  public static {};
  public int foo();
}
于 2012-03-04T17:27:36.763 に答える
2

これは不可能です。scalaobject ...では、Java クラスの静的メソッドを介してアクセスできるシングルトン インスタンスになるためです。例えば

object Foo {
  def bar = 2
}

次のようになります。

public final class Foo {
  public static int bar() {
    return Foo..MODULE$.bar();
  }
}

public final class Foo$
  implements ScalaObject
{
  public static final  MODULE$;

  static
  {
    new ();
  }

  public int bar()
  {
    return 2;
  }

  private Foo$()
  {
    MODULE$ = this;
  }
}

この場合、暗黙的な変換メソッドに渡されるのは、Foo$ 型のインスタンスである Foo..MODULE$ です。Java 静的には、基礎となるシングルトン インスタンスがないため、関数に渡して別の型に変換することはできません。

これがなぜそれが不可能なのかを理解するのに少し役立つことを願っています;-)。

于 2012-03-06T11:24:35.380 に答える
1

この種のシングルトン オブジェクトに暗黙的な変換によってメソッドを追加することはできませんが、暗黙的なパラメーターを使用して実際に作成することはできます。例えば:

trait Factory1[-A,+B] {
  def buildFrom( a: A ): B
}

trait Factory2[-A1,-A2,+B] {
  def buildFrom( a1: A1, a2: A2 ): B
}

object Factories {
  implicit object GeoPointFromLocation extends Factory1[Location,GeoPoint] {
    def buildFrom( location: Location ): GeoPoint = //actual code
  }
  implicit object GeoPointFromXY extends Factory2[Double,Double,GeoPoint] {
    def buildFrom( x: Double, y: Double ): GeoPoint = //actual code
  }
}

object GeoPoint {
  def from[A]( a: A )( implicit fac: Factory1[A,GeoPoint] ) = fac.buildFrom(a)
  def from[A,B]( a: A, b: B )( implicit fac: Factory2[A,B,GeoPoint] ) = fac.buildFrom(a,b)
}

import Factories._
val loc = new Location(...)
val gp1 = GeoPoint.from( loc )
val gp2 = GeoPoint.from( 101.0, -12.6 )

したがって、ファクトリは期待どおり「静的」ですが、GeoPointオブジェクトを変更することなく動作を強化または変更できます。たとえば、テスト時に特別なファクトリをインポートできます。

このアプローチは、Scala ライブラリで使用されます。たとえばTraversablemap.

于 2012-03-06T21:10:18.903 に答える
0

これは不可能ですが、パッケージ オブジェクトに同じクラス名のコンパニオン オブジェクトを用意して、必要に応じて使用することはできます。

import com.google.android.maps.GeoPoint

package object com.xyz.mappy.maps {
   object GeoPoint {        
     def from(....): GeoPoint = new GeoPoint(...)
   }
}


.................................

package com.xyz.mappy.maps

import com.google.android.maps.GeoPoint

class MapRenderer  {

  val geopoint = GeoPoint.from(...)

}    
于 2012-03-07T18:48:12.810 に答える
0

あなたがしたいことは不可能です。Java クラスは Scala オブジェクトではないため、メソッドで拡大する方法はありません。

作業をできるだけ簡単にする唯一のポイントは、Scala でオブジェクトを作成し、Java クラスの修飾付きインポートを作成することです。

import test.{ Test => JTest }
object Test {
  def anyMethodHere ...
}
于 2012-03-03T15:47:21.853 に答える