代码之家  ›  专栏  ›  技术社区  ›  Djura Marinkov

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

  •  2
  • Djura Marinkov  · 技术社区  · 6 年前

    所以我有一个类,它假定使用泛型类型,但是该类型应该具有某些特性

    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 [双] ?

    2 回复  |  直到 5 年前
        1
  •  4
  •   Travis Brown    6 年前

    你所描述的听起来在scala中是不可能的(它实际上没有在构造函数上进行抽象的工具),而且不知道你更具体的更大目标,很难提供好的建议,但是下面是一个scala惯用的解决方案,它提供了你想要的用法。 MyClass 这是专门设计的,允许您使用泛型类型,同时将这些类型约束为具有特定操作。

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

    trait Calculable[A] {
      def create(values: Seq[Double]): A
      def calculate(a: A): Double
    }
    

    您可以将这种类型的实例视为可以对某些 A .

    接下来你会写下你的 类名 这样地:

    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 可以是任何类型,只要我们知道如何做 可计算的 对它的操作”。

    现在您可以编写一个特定的类,它可以用作 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] 我的计算 伴随对象,但是类型类方法的一个优点是它将类型上的操作定义与类型的定义分开,并且这些实例可以单独定义。

        2
  •  0
  •   Djura Marinkov    5 年前

    我自己想出了一个答案,我想和大家分享…

    所以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的解决方案肯定更好,否则这可能是有用的…