在 Scala 中创建一个类型的新实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5302687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:54:29  来源:igfitidea点击:

creating a new instance of a type in scala

scalatypes

提问by Aaron Yodaiken

If I have a class C defined as

如果我有一个 C 类定义为

class C[A]

is there any way to create a new instance of Awithin C? Something like

有没有办法A在 C 中创建一个新实例?就像是

class C[A] {
  def f(): A = new A()
}

I understand that, if this were possible, you'd probably have to specify the constructor arguments somewhere, and that's fine.

我知道,如果可能的话,您可能必须在某处指定构造函数参数,这很好。

If it's not possible, are there any design patterns for dealing with the sort of situation where you'd like to create a new instance of a type?

如果不可能,是否有任何设计模式可以处理您想要创建类型的新实例的情况?

回答by Aaron Novstrup

You could use a type class to abstract instantiation:

您可以使用类型类来抽象实例化:

trait Makeable[T] {
   def make: T
}

class C[T: Makeable] {
   def f(): T = implicitly[Makeable[T]].make
}

For example,

例如,

implicit object StringIsMakeable extends Makeable[String] {
   def make: String = "a string"
}

val c = new C[String]
c.f // == "a string"

When you instantiate C, you'll need to provide, explicitly or implicitly, a Makeable that will act as a factory of the appropriate type. That factory, of course, would be responsible for supplying any constructor arguments when it invokes the constructor.

当您实例化 C 时,您需要显式或隐式地提供一个 Makeable,它将充当适当类型的工厂。当然,该工厂将负责在调用构造函数时提供任何构造函数参数。

Alternatively, you could use a Manifest, but be warned that this approach relies on reflection and is not type safe:

或者,您可以使用 Manifest,但要注意这种方法依赖于反射并且不是类型安全的:

class C[T: Manifest] {
   def f(): T = manifest[T].erasure.newInstance.asInstanceOf[T]
}

For completeness, you can also easily extend this approach to pass some or all of the constructor parameters in to the make method:

为了完整起见,您还可以轻松扩展此方法以将部分或全部构造函数参数传递给 make 方法:

trait Makeable[Args, T] { def make(a: Args): T }

class C[Args, T](implicit e: Makeable[Args, T]) {
   def f(a: Args): T = e.make(a)
}

// some examples
case class Person(firstName: String, lastName: String)

implicit val personFactory1 = new Makeable[(String, String), Person] {
   def make(a: (String, String)): Person = Person(a._1, a._2)
}
implicit val personFactory2 = new Makeable[String, Person] {
   def make(a: String): Person = Person(a, "Smith")
}

val c1 = new C[String, Person]
c1.f("Joe") // returns Person("Joe", "Smith")

val c2 = new C[(String, String), Person]
c2.f("John", "Smith") // returns Person("John", "Smith")

回答by Raphael

You can demand an implicit parameter, like so:

您可以要求一个隐式参数,如下所示:

class A[T](implicit newT : T) { 
  val t = newT 
} 

All you need then is to have an implicit factory of the desired type in scope when you instanciate A, e.g. the following works:

然后,您只需要在实例化时在范围内拥有所需类型的隐式工厂A,例如以下工作:

implicit def newSeq[T] = Seq[T]()                
val a = new A[Seq[String]]                            

As shown by:

如图所示:

scala> a.t
res22: Seq[String] = List()

回答by cfeduke

The same as @Raphael's answer with a case class's applymethod:

与@Raphael 对案例类apply方法的回答相同:

class Container[A](contained: A)
case class Person(name: String)
case class PersonContainer(person: Person) extends Container[Person](person)
implicit def _ = PersonContainer.apply _

class Creator {
  def deserializeAndPackage[A, B <: Container[A]](data: Array[Byte])
                           (implicit containerCreator: (A => B)): B = {
    val p = /* deserialize data as type of A */
    containerCreator(p)
  }
}