gpt4 book ai didi

scala - "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement"

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

当我编译时:

object Test extends App {
implicit def pimp[V](xs: Seq[V]) = new {
def dummy(x: V) = x
}
}

我得到:
$ fsc -d aoeu go.scala
go.scala:3: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
def dummy(x: V) = x
^
one error found

为什么?

( Scala: "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement" 并没有真正回答这个问题。)

最佳答案

规范不允许这样做。参见 3.2.7 复合类型。

Within a method declaration in a structural refinement, the type of any value parameter may only refer to type parameters or abstract types that are contained inside the refinement. That is, it must refer either to a type parameter of the method itself, or to a type definition within the refinement. This restriction does not apply to the function’s result type.



之前 Bug 1906被修复了,编译器会编译这个,你会得到一个在运行时找不到的方法。这已在 revision 19442 中修复这就是为什么你会收到这个美妙的信息。

那么问题来了,为什么不允许这样做呢?

这里很 detailed explanation来自 2007 年 scala 邮件列表中的 Gilles Dubochet。它大致归结为这样一个事实,即结构类型使用反射,并且编译器不知道如何查找要调用的方法,如果它使用在细化之外定义的类型(编译器提前不知道如何填写 p.getClass.getMethod("pimp", Array(?))中getMethod的第二个参数

但是去看看这个帖子,它会回答你的问题等等。

编辑:

你好名单。

I try to define structural types with abstract datatype in function parameter. ... Any reason?



我听说过关于结构类型的两个问题
最近 Scala 2.6 的扩展,我想在这里回答它们。
  • 为什么我们要更改 Scala 的原生值(“int”等)装箱方案
    到 Java(“java.lang.Integer”)。
  • 为什么对结构定义的参数有限制
    方法(“结构细化中的参数类型可能不引用
    抽象类型定义在相同的细化之外”)需要。

  • 在回答这两个问题之前,我需要先谈谈
    结构类型的实现。

    JVM 的类型系统非常基础(对应于 Java 1.4)。那
    意味着可以在 Scala 中表示的许多类型不能
    在 VM 中表示。路径依赖类型(“x.y.A”),单例类型
    (“a.type”)、复合类型(“A with B”)或抽象类型都是类型
    无法在 JVM 的类型系统中表示。

    为了能够编译为 JVM 字节码,Scala 编译器更改了
    程序的 Scala 类型到它们的“删除”(参见第 3.6 节)
    引用)。删除的类型可以在 VM 的类型系统中表示,并且
    在程序上定义一个类型规则,它等同于
    使用 Scala 类型键入的程序(保存一些强制转换),尽管更少
    精确的。作为旁注,类型在 VM 中被删除的事实
    解释了为什么对类型的动态表示进行操作(模式
    类型匹配)在 Scala 的类型方面非常受限制
    系统。

    到目前为止,Scala 中的所有类型结构都可以通过某种方式删除。
    这不适用于结构类型。简单结构类型“{ def
    x: Int }” 不能被删除为“Object”,因为 VM 不允许
    访问“x”字段。使用接口(interface)“interface X { int x{}; }”
    因为删除的类型也不起作用,因为任何实例都受
    这种类型的值必须实现那个不能的接口(interface)
    在单独编译的情况下完成。确实(忍受我)任何
    包含与定义的成员同名的成员的类
    任何地方的结构类型都必须实现相应的
    界面。不幸的是,这个类甚至可能在
    已知存在结构类型。

    相反,任何对结构定义成员的引用都被实现
    作为反射调用,完全绕过 VM 的类型系统。为了
    示例 def f(p: { def x(q: Int): Int }) = p.x(4)将被改写
    类似于:
      def f(p: Object) = p.getClass.getMethod("x", Array(Int)).invoke(p, Array(4))

    现在是答案。
  • “调用”将使用装箱(“java.lang.Integer”)值,只要
    调用的方法使用 native 值(“int”)。这意味着上述
    调用必须看起来像“...invoke(p, Array(new
    java.lang.Integer(4))).intValue”。

  • Scala 程序中的整数值已经经常被装箱(以允许
    “任何”类型),并且将它们从 Scala 自己的类型中拆箱是很浪费的
    装箱方案立即将它们重新装箱为 java.lang.Integer。

    最糟糕的是,当反射调用具有“Any”返回类型时,
    返回 java.lang.Integer 时应该怎么做?被称为
    方法可能会返回一个“int”(在这种情况下它应该是
    拆箱并重新装箱为 Scala 盒子)或者它可能会返回一个
    java.lang.Integer 应该保持不变。

    相反,我们决定将 Scala 自己的装箱方案更改为 Java 的。这
    之前的两个问题就消失了。一些性能相关的
    我们对 Scala 的装箱方案进行的优化(预先计算
    最常见数字的盒装形式)在 Java 中易于使用
    拳击也是。最后,使用 Java 拳击甚至比
    我们自己的方案。
  • “getMethod”的第二个参数是一个数组
    要查找的(结构定义的)方法的参数 - 用于
    选择名称重载时要获取的方法。这是
    在一个地方,在这个过程中需要精确的静态类型
    翻译结构成员调用。通常,可利用的静态类型
    为方法的参数提供了结构类型
    定义。在上面的例子中,“x”的参数类型是已知的
    是“Int”,它允许查找。

  • 参数类型定义为抽象类型,其中抽象类型为
    定义在结构细化范围内是没有问题的
    任何一个:
    def f(p: { def x[T](t: T): Int }) = p.xInt
    在这个例子中,我们知道任何作为“p”传递给“f”的实例都会
    定义“x[T](t: T)”,它必须被删除为“x(t: Object)”。这
    然后在已删除的类型上正确完成查找:
    def f(p: Object) = p.getClass.getMethod("x", Array(Object)).invoke(p,
    数组(new java.lang.Integer(4)))

    但是如果结构精修范围之外的抽象类型
    用于定义结构方法的参数,一切都中断了:
    def f[T](p: { def x(t: T): Int }, t: T) = p.x(t)
    当“f”被调用时,“T”可以被实例化为任何类型,例如:
    f[Int]({ def x(t: Int) = t }, 4)
    f[Any]({ def x(t: Any) = 5 }, 4)
    第一种情况的查找必须是“getMethod("x",
    Array(int))”和第二个“getMethod("x", Array(Object))”,以及
    无法知道在体内生成哪个
    “f”:“p.x(t)”。

    允许在“f”的主体内定义一个唯一的“getMethod”调用
    “T”的任何实例化都需要传递给“f”的任何对象作为
    “p”参数将“t”的类型删除为“Any”。这将是一个
    类成员的类型取决于如何转换
    此类的实例在程序中使用。这是什么
    我们绝对不想做(并且不能用单独的
    汇编)。

    或者,如果 Scala 支持运行时类型,则可以使用它们来
    解决这个问题。或许有一天 ...

    但是现在,使用抽象类型作为结构方法的参数
    类型是完全禁止的。

    真挚地,
    吉尔斯。

    关于scala - "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7830731/

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