![](/img/trans.png)
[英]In Scala, can I (would some SIP allow me to) specify only certain type parameters of a generic method?
[英]Is it possible to specify that a type will have a certain parameters in its constructor? Scala
所以我有一个假定使用通用类型的类,但是该类型应该具有某些特征
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]
构造函数呢?
您所描述的内容听起来似乎在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]
就是MyCalculation
随MyCalculation
对象,但是类型类方法的优点之一是它将类型操作与定义分开类型,这些实例可以分别定义。
我想自己分享一个答案...
因此,相反,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
替换Calc99
...
因此,如果您只有很少的计算器和对MyClass的大量调用,则肯定是Trevis的解决方案更好,否则,这可能会很有用...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.