gpt4 book ai didi

generics - 在 Scala 中是否可以强制调用者为多态方法指定类型参数?

转载 作者:行者123 更新时间:2023-12-03 21:23:05 25 4
gpt4 key购买 nike

//API
class Node
class Person extends Node

object Finder
{
def find[T <: Node](name: String): T = doFind(name).asInstanceOf[T]
}

//Call site (correct)
val person = find[Person]("joe")

//Call site (dies with a ClassCast inside b/c inferred type is Nothing)
val person = find("joe")

在上面的代码中,客户端“忘记”指定类型参数,作为 API 编写者,我希望这意味着“只返回节点”。有没有办法定义一个通用方法(不是一个类)来实现这个(或等效的)。注意:在实现中使用 list 进行强制转换 if (manifest != scala.reflect.Manifest.Nothing) 不会编译......我有一种 Scala 向导知道如何使用 Predef 的烦恼。<:<为了这 :-)

想法?

最佳答案

另一种解决方案是为参数指定默认类型,如下所示:

object Finder {
def find[T <: Node](name: String)(implicit e: T DefaultsTo Node): T =
doFind(name).asInstanceOf[T]
}

关键是定义以下幻像类型作为默认值的见证:
sealed class DefaultsTo[A, B]
trait LowPriorityDefaultsTo {
implicit def overrideDefault[A,B] = new DefaultsTo[A,B]
}
object DefaultsTo extends LowPriorityDefaultsTo {
implicit def default[B] = new DefaultsTo[B, B]
}

这种方法的优点是它完全避免了错误(在运行时和编译时)。如果调用者没有指定类型参数,则默认为 Node .

解释 :
find 的签名方法确保只有在调用者可以提供 DefaultsTo[T, Node] 类型的对象时才能调用它。 .当然, defaultoverrideDefault方法可以很容易地为任何类型创建这样的对象 T .由于这些方法是隐式的,编译器会自动处理调用其中一个并将结果传递给 find 的业务。 .

但是编译器怎么知道调用哪个方法呢?它使用其类型推断和隐式解析规则来确定适当的方法。有三种情况需要考虑:
  • find不带类型参数调用。在这种情况下,键入 T必须推断。搜索可以提供 DefaultsTo[T, Node] 类型对象的隐式方法,编译器找到 defaultoverrideDefault . default之所以选择它,是因为它具有优先级(因为它是在定义 overrideDefault 的特征的适当子类中定义的)。结果,T必须绑定(bind)到 Node .
  • find用非 Node 调用类型参数(例如,find[MyObj]("name"))。在这种情况下,类型为 DefaultsTo[MyObj, Node] 的对象必须提供。只有 overrideDefault方法可以提供它,因此编译器插入适当的调用。
  • findNode 调用作为类型参数。同样,这两种方法都适用,但 default由于优先级较高而获胜。
  • 关于generics - 在 Scala 中是否可以强制调用者为多态方法指定类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4403906/

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