Scala:如何在编译时不知道类型的情况下使用类型参数和清单调用方法?

Ale*_*yda 4 reflection types scala implicit

我有一个具有以下签名的函数:

myFunc[T <: AnyRef](arg: T)(implicit m: Manifest[T]) = ???
Run Code Online (Sandbox Code Playgroud)

如果在编译时我不知道参数的确切类型,我该如何调用此函数?

例如:

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?
Run Code Online (Sandbox Code Playgroud)

我想写一些逻辑类似的东西:

myFunc[objClass](obj.asInstanceOf[objClass])
Run Code Online (Sandbox Code Playgroud)

谢谢!

更新:

问题是无效的 - 正如@DaoWen,@ Jermo和@itsbruce正确指出的那样,我试图做的事情完全是胡说八道!我只是严厉地推翻了这个问题.感谢你们!太糟糕了我不能接受所有答案正确:)

所以,问题是由以下情况引起的:

我正在使用Salat库将对象序列化为BSON/JSON表示/从BSON/JSON表示. Salat有一个Grater[T]用于序列化和反序列化的类.从BSON 调用反序列化的方法看起来像这样:

val foo = grater[Foo].asObject(bson)
Run Code Online (Sandbox Code Playgroud)

这里,类型参数的作用是明确的.我试图做的是使用相同的Grater来序列化我的域模型中的任何实体.所以我写道:

val json = grater[???].toCompactJSON(obj)
Run Code Online (Sandbox Code Playgroud)

我立即赶紧反思,只是没有看到表面上有明显的解决方案.这是:

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

@Salat trait Entity                // is a root of the domain model hierarchy
Run Code Online (Sandbox Code Playgroud)

有时事情比我们想象的容易得多!:)

Vla*_*eev 5

看来,当我写这个答案时,问题的作者意识到他不需要Manifest在运行时解决问题.但是,在我看来,当我编写Yaml [de]序列化库时,我成功解决了完全合法的问题,所以我在这里留下答案.


使用ClassTags甚至TypeTags 可以做你想做的事.我不知道Manifests,因为该API已被弃用,我没有使用它,但我相信,由于它们不像新的Scala反射那样复杂,因此它会更容易.仅供参考,其Manifest继任者是TypeTag.

假设您具有以下功能:

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

def useTypetag[T: TypeTag](obj: T) = ...
Run Code Online (Sandbox Code Playgroud)

你需要与再调用obj: AnyRef作为参数,同时提供两种ClassTagTypeTagobj.getClass类的隐含参数.

ClassTag是最容易的.您可以ClassTag直接从Class[_]实例创建:

useClasstag(obj)(ClassTag(obj.getClass))
Run Code Online (Sandbox Code Playgroud)

就这样.

TypeTags更难.您需要使用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)
Run Code Online (Sandbox Code Playgroud)

如您所见,这种机器相当复杂.这意味着你只有在你真正需要的时候才能使用它,正如其他人所说的那样,你真正需要它的情况非常罕见.