如何获取与上下文绑定关联的类型类的实例?
注意:我提出这个问题是为了自己回答,但欢迎其他答案。
考虑以下简单方法:
def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y)
我可以使用 上下文绑定如下,
def add[T: Numeric](x: T, y: T) = ??.plus(x,y)
但如何获取 Numeric[T]
类型的实例我可以调用 plus
方法吗?
Note: I'm posing this question to answer it myself, but other answers are welcome.
Consider the following simple method:
def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y)
I can rewrite this using a context bound as follows
def add[T: Numeric](x: T, y: T) = ??.plus(x,y)
but how do I get an instance of the Numeric[T]
type so that I can invoke the plus
method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用隐式方法
最常见和通用的方法是使用隐式方法,在Predef中定义:
显然,这有点冗长,需要重复类型类的名称。
引用证据参数(不要!)
另一种选择是使用编译器自动生成的隐式证据参数的名称:
令人惊讶的是,这种技术甚至是合法的,并且在实践中不应该依赖它,因为证据参数的名称可能会改变。
更高类型的上下文(引入
上下文
方法)相反,我们可以使用
隐式
的增强版本代码>方法。请注意,隐式方法被定义为:该方法仅依赖于编译器将正确类型的隐式对象从周围范围插入到方法调用中,然后返回它。我们可以做得更好一点:
这允许我们将
add
方法定义为context
方法类型参数Numeric
和T 是从范围推断出来的!不幸的是,在某些情况下这个
context
方法不起作用。例如,当类型参数具有多个上下文边界或存在具有不同上下文边界的多个参数时。我们可以用稍微复杂的版本来解决后一个问题:这个版本要求我们每次都指定类型参数,但可以处理多个类型参数。
Using the implicitly method
The most common and general approach is to use the implicitly method, defined in Predef:
Obviously, this is somewhat verbose and requires repeating the name of the type class.
Referencing the evidence parameter (don't!)
Another alternative is to use the name of the implicit evidence parameter automatically generated by the compiler:
It's surprising that this technique is even legal, and it should not be relied upon in practice since the name of the evidence parameter could change.
Context of a Higher Kind (introducing the
context
method)Instead, one can use a beefed-up version of the
implicitly
method. Note that the implicitly method is defined asThis method simply relies on the compiler to insert an implicit object of the correct type from the surrounding scope into the method call, and then returns it. We can do a bit better:
This allows us to define our
add
method asThe
context
method type parametersNumeric
andT
are inferred from the scope! Unfortunately, there are circumstances in which thiscontext
method will not work. When a type parameter has multiple context bounds or there are multiple parameters with different context bounds, for example. We can resolve the latter problem with a slightly more complex version:This version requires us to specify the type parameter every time, but handles multiple type parameters.
至少从 Scala 2.9 开始你可以执行以下操作:
At least since Scala 2.9 you can do the following:
这个答案描述了另一种方法,该方法可以产生更具可读性、自文档化的客户端代码。
动机
我之前描述的
context
方法是一个非常通用的解决方案,适用于任何类型类,无需任何额外的工作。但是,由于以下两个原因,这可能是不可取的:当类型参数具有多个上下文边界时,不能使用
context
方法,因为编译器无法确定要使用哪个上下文边界。< /p>对通用
context
方法的引用损害了客户端代码的可读性。特定于类型类的方法
使用与所需类型类相关的方法可以使客户端代码更具可读性。这是标准库中用于 Manifest 类型类的方法:
概括此方法
使用特定于类型类的方法的主要缺点是必须为每个类型类定义一个附加方法。我们可以通过以下定义简化此过程:
然后可以为任何类型类定义新的特定于类型类的隐式样式方法:
最后,客户端代码可以按如下方式使用隐式:
This answer describes another approach that results in more-readable, self-documenting client code.
Motivation
The
context
method that I described previously is a very general solution that works with any type class, without any additional effort. However, it may be undesirable for two reasons:The
context
method cannot be used when the type parameter has multiple context bounds, since the compiler has no way to determine which context bound is intended.The reference to the generic
context
method harms readability of the client code.Type-class-specific methods
Using a method that is tied to the desired type class makes client code much more readable. This is the approach used in the standard library for the Manifest type class:
Generalizing this approach
The main drawback of using type-class-specific methods is that an additional method must be defined for every type class. We can ease this process with the following definitions:
Then a new type-class-specific implicitly-style method can be defined, for any type class:
Finally, client code can use the Implicitly as follows: