我正在Scala中学习上下文绑定。
在下面的代码中,我调用整数参数的乘法运算符。但它错了a’被认为是类型参数;但实际上并不是按照我的理解。有人能帮忙吗。
scala> class Sample[T]
defined class Sample
scala> def method[Int:Sample](a:Int) = a * a
<console>:12: error: value * is not a member of type parameter Int
def method[Int:Sample](a:Int) = a * a
谢谢!
上下文边界是隐式泛型参数的语法糖,这些参数由您使用的某种类型参数化。这个概念也被称为";类型类";。定义一些通用特征,例如Sample[T]
,然后为T
的各种具体值提供该特征的隐式(!(实例。我们称之为";类型类实例";。
为什么是隐含的?这是Scala用来实现类型类机制的实现细节;类型类也存在于例如Haskell中,但机制本身有点不同。无论如何,您可以定义一个方法,例如def method
,它需要某个类型的类型类实例。您可以使用上下文绑定语法,或者使用更详细、更明确的隐式参数标准语法来实现这一点。
您的定义是使用上下文绑定的。但是,正如编译错误所表明的那样,您的示例有问题。让我们首先看一个正确使用类型类概念的示例。
// type class definition:
trait Sample[T] {
def getSample: T
}
// type class instance(s):
object Sample {
implicit val sampleInt: Sample[Int] =
new Sample[Int] { def getSample = 42 }
}
现在的用法:
import Sample._
// using the context bound syntax
def method1[T : Sample](t: T) = t.getSample
// not using the context bound syntax
def method2(t: T)(implicit ev: Sample[T]) = t.getSample
我们正在做的是说-有一些T
类型的值t
,我们对此了解不多,但我们知道有一个Sample
类型的类实例可用于它。这允许我们执行t.getSample
。
现在,最终为您的问题提供答案:
在你的代码中,你把事情搞混了。您的T
实际上被称为Int
。您打算使用Int
类型,但实际操作是将泛型参数命名为Int
。我本可以用更少的文字来回答这个问题,但我想也许你会觉得大局很有趣,而不仅仅是指出错误。
名为Int
的类型参数不表示具体的整数类型scala.Int
。相反,类型参数被赋予与具体类型相同的名称Int
,这只是一个令人困惑的巧合。如果你给它取一些其他的名字,比如T
def method[T: Sample](a: T): T = a * a
错误消息应该更有意义。现在我们看到*
没有为T
定义,因为Sample
类型类还没有提供这样的能力。下面是一个正确的语法用法看起来如何使用的例子
trait Sample[T] {
def mult(a: T, b: T): T
}
def method[T: Sample](a: T): T = implicitly[Sample[T]].mult(a, a)
def method[T](a: T)(implicit ev: Sample[T]): T = ev.mult(a, a)
您还可以查看Numeric
类型的类,它提供了开箱即用的功能
def method[T](a: T)(implicit num: Numeric[T]): T = num.times(a, a)
您的方法有一个名为Int
的类型参数,它会对实际的Int
进行阴影处理,就像定义一个普通变量会对外部范围的某些内容进行阴影处理一样。如果删除上下文绑定,也会发生同样的情况。
你可能想做的是更接近以下的事情:
trait Sample[A] {
def someOperation(a1: A, a2: A): A
}
implicit object IntSample extends Sample[Int] {
override def someOperation(a1: Int, a2: Int): Int = a1 * a2
}
def method[T: Sample](t: T) = implicitly[Sample[T]].someOperation(t, t)
method(4) // compiles and returns 16
//method("4") // doesn't compile, no implicit instance of Sample[String] in scope
你可以在Scastie上玩这个代码。