所以我有一个假定使用通用类型的类,但是该类型应该具有某些特征
calculate
Seq[Double]
此刻我有个特征
trait HasCalculate {def calculate(): Double}
我以这种方式使用它:
val pars = Seq(1.0, 2.0)
val calc = new Calc1(pars) with HasCalculate
val res = calc.calculate
当我想使用另一个计算器时,将Calc2代替Calc1放在类的代码中。但是我想用通用的方式来做,就像这样:
class MyClass[T]{
val pars = Seq(1.0, 2.0)
val calc = new T(pars) with HasCalculate
val res = calc.calculate
}
但是如何定义T
具有接受Seq[Double]
的构造函数?
答案 0 :(得分:4)
您所描述的内容听起来好像在Scala中是不可能的(它实际上没有用于构造函数抽象的功能),并且在没有更具体地了解您的较大目标的情况下,很难提供良好的建议,但是以下是一种Scala惯用的解决方案,提供MyClass
所需要的使用方式,并且经过专门设计,可让您使用通用类型,同时将这些类型限制为具有某些操作。
第一步是编写一个 type类来捕获所需的操作:
trait Calculable[A] {
def create(values: Seq[Double]): A
def calculate(a: A): Double
}
您可以将此类型的实例视为“证据”,可以对某些A
执行这些操作。
接下来,您将像这样写MyClass
:
class MyClass[T: Calculable] {
private val instance = implicitly[Calculable[T]]
val pars = Seq(1.0, 2.0)
val calc: T = instance.create(pars)
val res: Double = instance.calculate(calc)
}
T: Calculable
部分是一个“上下文绑定”,它指定必须有隐式证据证明T
具有一个Calculable
实例。这是一个约束条件,规定“ T
可以是任何类型,只要我们知道如何对其执行Calculable
操作。”
现在,您可以像这样编写一个可以用作T
的特定类:
class MyCalculation(vs: Seq[Double]) {
def calculate(): Double = vs.sum
}
object MyCalculation {
implicit val calculableInstance: Calculable[MyCalculation] =
new Calculable[MyCalculation] {
def create(values: Seq[Double]): MyCalculation = new MyCalculation(values)
def calculate(a: MyCalculation): Double = a.calculate()
}
}
您将获得所需的用法:
scala> val myClass = new MyClass[MyCalculation]
myClass: MyClass[MyCalculation] = MyClass@646bf8a6
scala> myClass.res
res0: Double = 3.0
如果您控制MyCalculation
的定义,则最方便地定义其隐式Calculable[MyCalculation]
的地方是MyCalculation
伴随对象,但是类型类方法的优点之一是:它将类型操作的定义与类型的定义分开,这些实例可以分别定义。
答案 1 :(得分:0)
我想自己分享一个答案...
因此,MyClass具有类型参数,它可以具有函数作为参数,如下所示:
class MyClass(f:(Seq[Double])=>HasCalculate){
val pars = Seq(1.0, 2.0)
val calc = f(pars)
val res = calc.calculate
}
然后在其主体中提供一个带有构造函数的匿名函数:
val myClass = new MyClass((s:Seq[Double])=>new Calc1(s) with HasCalculate)
当然这看起来很丑陋,但就我而言,它似乎比Travis的解决方案更实用,因为我有很多计算器,并且我不打算为每个计算器或每次运行时都创建该工厂对象通过MyClass
的计算器。我只是复制这一行代码,然后将Calc1
替换为Calc99
...
因此,如果您只有很少的计算器和对MyClass的大量调用,那么肯定是Trevis的解决方案更好,否则可能会有用...