Scala中的上下文绑定



我正在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上玩这个代码。

最新更新