【问题标题】:Could not find implicit value for parameter找不到参数的隐式值
【发布时间】:2017-02-02 10:24:32
【问题描述】:

我最近开始学习 Scala 的隐式“魔法”,但我在使用隐式 Scala 对象时遇到了麻烦。我已经尝试了所有可能的变体,但似乎没有任何效果。

假设我有一个像这样的类,带有一些 solve() 函数。如果输入 a、b 是浮点数,它应该返回 2 个浮点值。否则它应该返回另一个类型值:

class Solver[T](val a: T, val b: T) {
    def solve[A](implicit num: customNumeric[T]): Option[(T, T)] = {
        Option(
            num.f(num.g(a)),
            num.f(num.g(b)))
    }
}

让我们假设另一个类型值是这样的类的对象:

class MyClass[T] (x: T, y: T)(implicit num: customNumeric[T]) {
    val field : T = num.f(x)
}

我们还假设我没有基本 Scala Numeric 中需要的函数,所以我应该制作自己的自定义数字。

这是我所做的:

我用我的方法 f() 和 g() 以及几个隐式对象为我自己的 customNumeric 创建了一个抽象类,这些对象为某些值类型(例如 Int、Float)扩展了我的 customNumeric 并在其中实现了方法:

abstract class customNumeric[T] {
    def f(x: T): T
    def g(x: T): T
}

object customNumeric {
    implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]] {
        def f(x: MyClass[Int]) = new MyClass[Int](x.field + 5)
        def g(x: MyClass[Int]) = new MyClass[Int](x.field - 5)
    }
    implicit object FloatIsCustomNumeric extends customNumeric[Float] {
        def f(x: Float): Float = x + 3
        def g(x: Float): Float = x - 3
    }
}

在我看来,Solver 的solve() 应该使用隐式customNumeric 对象来根据Solver 的输入值的类型来获取在solve() 中引用的方法的实现。

但这并不像编译器所说的那样工作:

could not find implicit value for parameter num: customNumeric[Int]
        def f...

它还抱怨构造函数MyClass 在同一行没有足够的参数。

我已经尝试让伴生对象将Int 转换为MyClass

object Fraction {
    implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
}

但这似乎也不起作用。而且我尝试制作另一个隐式对象来实现我在 customNumeric[MyClass[Int]] 中使用的方法。

你有什么想法吗?提前致谢!

【问题讨论】:

    标签: scala implicit


    【解决方案1】:

    问题是您试图使用本身需要相同隐式对象的类来定义隐式对象。

    意思,这个:

    class MyClass[T] (x: T, y: T)(implicit num: CustomNumeric[T])
    

    需要存在隐式CustomNumeric[T]。您不能使用该类型定义 IntIsCustomNumeric

    implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]]
    

    当你实现IntIsCustomNumeric时,你需要为Int类型实现它,而不是MyClass[Int]类型。当你这样做时,即:

    object CustomNumeric {
      implicit object IntIsCustomNumeric extends CustomNumeric[Int] {
        override def f(x: Int): Int = x
        override def g(x: Int): Int = x
      }
    }
    

    现在,您可以创建一个 Solver[Int],它采用隐式 CustomNumeric[Int]

    def main(args: Array[String]): Unit = {
      import CustomNumeric._
    
      val solver = new Solver[Int](1, 2)
      println(solver.solve)
    }
    

    现在,创建从 Int 类型到创建 MyClass[Int] 的类型的隐式转换也更容易:

    implicit object MyClassIsCustomNumeric extends CustomNumeric[MyClass[Int]] {
      override def f(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 5)
      override def g(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 3)
    }
    
    implicit def intToMyClass(i: Int) = new MyClass[Int](i)
    

    【讨论】:

    • 感谢您提供如此详细的答案!我想我知道Solver 将使用IntIsCustomNumeric 对象,然后通过intToMyClass 转换方法将其隐式转换为MyClass(具有方法实现)。但是试图调试这个转换的执行让我想到编译器如何知道IntIsCN 是否应该转换为MyClassIsCN,因为IntIsCN 具有完整的方法实现。因此它可以仅使用IntIsCN 的方法执行所有操作。还有一个问题 - 如果f(x:Int) 不返回Int 怎么办
    【解决方案2】:

    你怎么看这个

    object customNumeric {
    
      implicit object IntIsCustomNumeric extends customNumeric[Int] {
        def f(x: Int): Int = x + 3
    
        def g(x: Int): Int = x - 3
      }
    
      implicit object FloatIsCustomNumeric extends customNumeric[Float] {
        def f(x: Float): Float = x + 3
    
        def g(x: Float): Float = x - 3
      }
    
      implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
    
      implicit object cn extends customNumeric[MyClass[Int]] {
        def f(x: MyClass[Int]) = x.field + 5
    
        def g(x: MyClass[Int]) = x.field - 5
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-17
      • 2011-10-17
      • 2016-03-31
      • 2015-01-27
      • 1970-01-01
      • 2016-02-27
      • 2016-02-22
      • 2011-04-15
      • 2015-06-28
      相关资源
      最近更新 更多