繁体   English   中英

是否可以指定类型在其构造函数中具有某些参数? 斯卡拉

[英]Is it possible to specify that a type will have a certain parameters in its constructor? Scala

所以我有一个假定使用通用类型的类,但是该类型应该具有某些特征

  1. 它需要有定义的方法calculate
  2. 它需要具有接受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]构造函数呢?

您所描述的内容听起来似乎在Scala中是不可能的(它实际上没有用于构造函数的抽象工具),并且在没有更具体地了解您的较大目标的情况下,很难提供好的建议,但是以下是Scala-惯用的解决方案,提供了MyClass ,并且经过专门设计,可让您使用通用类型,同时将这些类型限制为具有某些操作。

第一步是编写一个捕获您需要的操作的类型类

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]就是MyCalculationMyCalculation对象,但是类型类方法的优点之一是它将类型操作与定义分开类型,这些实例可以分别定义。

我想自己分享一个答案...

因此,相反,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 我只是复制这一行代码, Calc1Calc99替换Calc99 ...

因此,如果您只有很少的计算器和对MyClass的大量调用,则肯定是Trevis的解决方案更好,否则,这可能会很有用...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM