gpt4 book ai didi

Scala:同一范围内的类型类、默认和自定义隐式转换

转载 作者:行者123 更新时间:2023-12-04 16:05:58 25 4
gpt4 key购买 nike

我想知道是否有一种优雅的方法可以在同一范围内同时进行默认隐式转换和一些用户定义的自定义转换。我有以下用例:

  1. 假设我们有一个特征,它为泛型 E 定义了一些二进制操作(例如 PlusSupport,它定义了 plus(x, y)) >
  2. 我们可以在可以转换为 PlusSupport 的对象上添加 "+" 语法,为此我们需要提供隐式转换
  3. 对于许多不同的类型,我们库的用户总是有很多到 PlusSupport 的默认隐式转换,例如将它们导入import defaultConversions._(全部导入,不要想太多)
  4. 现在,用户为某些类型添加了一些自定义隐式转换 (implicit val customConversion = ...),该类型已经具有来自 import defaultConversions._ 的默认转换(这自定义转换可以是用户编写的,也可以由第三方库 com.3dparty.veryAdvancedConversions.AwesomePlus 提供);用户希望使用他的自定义转换

这是代码示例:

trait A // some type A
trait B // some type B
// ... many other types goes here

// some binary operation
trait PlusSupport[E] {
def plus(a: E, b: E): E
}

object defaultConversions {
// default conversion of A to PlusSupport[A]
implicit def mkPlusSupportForA: A => PlusSupport[A] = _ => (a1: A, a2: A) => a1

// default conversion of B to PlusSupport[B]
implicit def mkPlusSupportForB: B => PlusSupport[B] = _ => (b1: B, b2: B) => b1

// ... many other conversions goes here
}

// + operator for elements with PlusSupport
class PlusOps[E](lhs: E)(plus: PlusSupport[E]) {
def +(rhs: E): E = plus.plus(lhs, rhs)
}

// adds "+" syntax
trait PlusSyntax {
implicit def plusOps[E](lhs: E)(implicit mkPlusSupport: E => PlusSupport[E]): PlusOps[E]
= new PlusOps[E](lhs)(mkPlusSupport(lhs))
}

object syntax extends PlusSyntax


def main(args: Array[String]): Unit = {
// import all default conversions for A, B, C, D etc. etc.
import defaultConversions._
import syntax._

// setup my custom conversion for A
implicit val myCustomPlusForA: A => PlusSupport[A] = _ => (a1: A, a2: A) => a2

val a1: A = new A {}
val a2: A = new A {}
val b1: B = new B {}
val b2: B = new B {}

// myCustomPlusForA should be used
println((a1 + a2) == a1)
println((a1 + a2) == a2)

// default conversion for B should be used
println((b1 + b2) == b1)
println((b1 + b2) == b2)

}

它没有编译并出现以下错误:

Error:(52, 19) type mismatch;
found : A
required: String
println((a1 + a2) == a1)

可以通过两种方式更正代码:

  1. 我们可以删除 implicit val myCustomPlusForA - 一切都会正常工作,将使用 defaultConversions 的默认隐式转换;但我们需要完全使用我的自定义转换,所以这不是一个选项

  2. 我们可以将 import defaultConversions._ 更改为 import defaultConversions.{everything except conversion for A} 然后 myCustomPlusForA 将是用过的 ;但这也是一个糟糕的选择,因为库的用户不会关心它(用户只想导入所有“默认值”并添加一些“自定义”,例如他可以使用 implicit val myCustomPlusForA 没有 implicit 关键字(所有编译都很好),而不是添加 implicit 只是为了测试完全自定义如何改变)

所以问题是如何修复代码,以便 import defaultConversions._implicit val myCustomPlusForA 都在相同的范围内并且完全 myCustomPlusForA 将被编译器使用?应使用哪种代码模式来实现所需的行为?

更新:我目前找到的解决方法是 use default value对于隐式参数并完全删除 import defaultConversions._(甚至将 defaultConversions 设为私有(private)以避免用户使用它):

private def defaultMk[E](ev: E): E => PlusSupport[E] = ev match {
case _: A => mkPlusSupportForA.asInstanceOf[E => PlusSupport[E]]
case _: B => mkPlusSupportForB.asInstanceOf[E => PlusSupport[E]]
case _ => ???
}

trait PlusSyntax {
implicit def plusOps[E](lhs: E)(implicit mkPlusSupport: E => PlusSupport[E]
= defaultConversions.defaultMk(lhs)): PlusOps[E] = new PlusOps[E](lhs)(mkPlusSupport(lhs))
}

但是在运行时进行检查确实看起来很奇怪,而所有信息在编译时都是可用的,编译器应该只是“替换”正确的转换。

最佳答案

正如@JesperNordenberg 在评论中建议的那样,可以使用隐式优先级排序。因此,为了使事情正常进行,只需将方法从 defaultConversions 移动到 PlusSupport 的伴随对象并完全删除 defaultConversions:

trait PlusSupport[E] {
def plus(a: E, b: E): E
}

// place default implicit conversions into companion object
private object PlusSupport {
// default conversion of A to PlusSupport[A]
implicit def mkPlusSupportForA: A => PlusSupport[A] = _ => (a1: A, a2: A) => a1

// default conversion of B to PlusSupport[B]
implicit def mkPlusSupportForB: B => PlusSupport[B] = _ => (b1: B, b2: B) => b1

// ... many other conversions goes here
}


def main(args: Array[String]): Unit = {
// no need to import from object PlusSupport

import syntax._

// setup my custom conversion for A
implicit val myCustomPlusForA: A => PlusSupport[A] = _ => (a1: A, a2: A) => a2

val a1: A = new A {}
val a2: A = new A {}
val b1: B = new B {}
val b2: B = new B {}

// myCustomPlusForA will be used
println((a1 + a2) == a1)
println((a1 + a2) == a2)

// default conversion for B will be used
println((b1 + b2) == b1)
println((b1 + b2) == b2)

}

关于Scala:同一范围内的类型类、默认和自定义隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46527763/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com