4

次のシグネチャを持つ関数があります。

myFunc[T <: AnyRef](arg: T)(implicit m: Manifest[T]) = ???

コンパイル時に引数の正確な型がわからない場合、どうすればこの関数を呼び出すことができますか?

例えば:

val obj: AnyRef = new Foo()    // At compile time obj is defined as AnyRef,
val objClass = obj.getClass    // At runtime I can figure out that it is actually Foo
// Now I would need to call `myFunc[Foo](obj.asInstanceOf[Foo])`,
// but how would I do it without putting [Foo] in the square braces?

論理的に次のようなものを書きたいと思います。

myFunc[objClass](obj.asInstanceOf[objClass])

ありがとうございました!

アップデート:

質問は無効です-@DaoWen、@Jelmo、および@itsbruceが正しく指摘したように、私がやろうとしていたことは完全にナンセンスでした! 私はその問題を真剣に考えすぎました。君たちありがとう!残念ながら、すべての答えを正しいものとして受け入れることはできません:)

したがって、問題は次の状況によって引き起こされました。

Salatライブラリを使用して、オブジェクトを BSON/JSON 表現との間でシリアル化しています。 シリアライゼーションとデシリアライゼーションの両方に使用されるクラスがありますSalatBSON からの逆シリアルGrater[T]化のメソッド呼び出しは次のようになります。

val foo = grater[Foo].asObject(bson)

ここで、型パラメーターの役割は明らかです。私がやろうとしていたのは、同じ Grater を使用して、ドメイン モデルからエンティティをシリアル化することです。だから私は書いた:

val json = grater[???].toCompactJSON(obj)

私はすぐに考えを巡らせましたが、明らかな解決策が表面にあるとは思いませんでした。それは次のとおりです。

grater[Entity].toCompactJSON(obj)  // where Entity...

@Salat trait Entity                // is a root of the domain model hierarchy

物事は私たちが思っているよりもはるかに簡単な場合があります! :)

4

4 に答える 4

5

Manifestこの回答を書いているときに、質問の作成者は、実行時に sを解決する必要がないことに気付いたようです。しかし、私の意見では、Yaml [de]serialization ライブラリを書いていたときにうまく解決したのは完全に法的な問題なので、ここに答えを残しておきます。


ClassTags またはsを使用して、必要なことを行うことができますTypeTag。sについてManifestはその API は非推奨であり、使用したことがないためわかりませんが、新しい Scala リフレクションほど洗練されていないため、マニフェストを使用すると簡単になると思います。参考までに、Manifestの後継者はTypeTagです。

次の関数があるとします。

def useClasstag[T: ClassTag](obj: T) = ...

def useTypetag[T: TypeTag](obj: T) = ...

そして、暗黙のパラメーターとしてクラスまたはクラスのいずれかをobj: AnyRef提供しながら、引数としてthen を呼び出す必要があります。ClassTagTypeTagobj.getClass

ClassTag最も簡単なものです。インスタンスClassTagから直接作成できます。Class[_]

useClasstag(obj)(ClassTag(obj.getClass))

それで全部です。

TypeTagは難しいです。オブジェクトからオブジェクトを取得するには Scala リフレクションを使用する必要があり、次に Scala リフレクションの内部を使用する必要があります。

import scala.reflect.runtime.universe._
import scala.reflect.api
import api.{Universe, TypeCreator}

// Obtain runtime mirror for the class' classloader
val rm = runtimeMirror(obj.getClass.getClassLoader)

// Obtain instance mirror for obj
val im = rm.reflect(obj)

// Get obj's symbol object
val sym = im.symbol

// Get symbol's type signature - that's what you really want!
val tpe = sym.typeSignature

// Now the black magic begins: we create TypeTag manually
// First, make so-called type creator for the type we have just obtained
val tc = new TypeCreator {
  def apply[U <: Universe with Singleton](m: api.Mirror[U]) =
    if (m eq rm) tpe.asInstanceOf[U # Type]
    else throw new IllegalArgumentException(s"Type tag defined in $rm cannot be migrated to other mirrors.")
}
// Next, create a TypeTag using runtime mirror and type creator
val tt = TypeTag[AnyRef](rm, tc)

// Call our method
useTypetag(obj)(tt)

ご覧のとおり、この機構はかなり複雑です。本当に必要な場合にのみ使用する必要があることを意味し、他の人が言ったように、本当に必要な場合は非常にまれです.

于 2013-09-19T19:08:06.047 に答える
3

これはうまくいきません。このように考えてみてください:実行時までわからないクラスのクラス マニフェストを (コンパイル時に!) 作成するようにコンパイラに要求しています。

しかし、あなたは間違った方法で問題に取り組んでいると感じています。コンパイル時AnyRefの型について知っているのは本当に一番ですか? Fooその場合、どうすればそれを使って何か役に立つことができますか? ( に対して定義されているいくつかのメソッドを除いて、メソッドを呼び出すことはできませんAnyRef。)

于 2013-09-19T13:53:11.720 に答える
0

これは、タイプ セーフな OO 言語を使用する間違った方法です。これを行う必要がある場合は、設計が間違っています。

myFunc[T <: AnyRef](arg: T)(implicit m: Manifest[T]) = ???

もちろん、これは役に立たないことです。何でもよいオブジェクトに対して、どのような意味のある関数を呼び出すことができますか? そのプロパティまたはメソッドを直接参照することはできません。

論理的に次のようなものを書きたいと思います。

myFunc[objClass](obj.asInstanceOf[objClass])

なんで?この種のことは、通常、非常に特殊な場合にのみ必要です。たとえば、依存性注入を使用するフレームワークを作成していますか? Scala の機能の高度に技術的な拡張を行っていない場合、これは必要ありません。

あなたは正確な型がわからないと言っているので、クラスについてもっと知っているに違いありません。クラスベースの OO が機能する方法の大きな部分の 1 つは、オブジェクトの一般的なタイプ (そのすべてのサブタイプを含む) に対して何かをしたい場合、その動作をクラスに属するメソッドに入れることです。必要に応じて、サブクラスがそれをオーバーライドできるようにします。

率直に言って、あなたが試みていることを行う方法は、型について十分に知っているコンテキストで関数を呼び出すことです。

于 2013-09-19T14:40:11.520 に答える