加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – “结构细化中的参数类型可能不会引用在该细化之外定义

发布时间:2020-12-16 09:28:27 所属栏目:安全 来源:网络整理
导读:当我编译: object Test extends App { implicit def pimp[V](xs: Seq[V]) = new { def dummy(x: V) = x }} 我明白了: $ fsc -d aoeu go.scalago.scala:3: error: Parameter type in structural refinement may not refer to an abstract type defined outs
当我编译:

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 re?nement,the type of any value parameter may only refer to type parameters or abstract types that are contained inside the re?nement. That is,it must refer either to a type parameter of the method
itself,or to a type de?nition within the re?nement. This restriction does not apply
to the function’s result type.

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

问题是,为什么不允许这样做?

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

但是看看帖子,它会回答你的问题,还有更多。

编辑:

你好清单。

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}“无法删除”虚拟机不允许的“对象”
访问“x”字段。使用接口“interface X {int x {}; }”
因为擦除类型将无法工作,因为任何绑定的实例
这种类型的值必须实现那个不能的接口
在单独编译的情况下完成。确实(忍受我)任何
包含与其中定义的成员同名的成员的类
任何地方的结构类型都必须实现相应的
接口。不幸的是,这个类甚至可以在之前定义
已知结构类型存在。

相反,实现了对结构定义的成员的任何引用
作为反射调用,完全绕过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))

现在的答案。

>“invoke”将使用boxed(“java.lang.Integer”)值
invoked方法使用本机值(“int”)。这意味着以上
call必须看起来像“… invoke(p,Array(new
java.lang.Integer中(4)))。的intValue”。

Scala程序中的整数值通常已经装箱(允许使用
“任何”类型)从Scala自己拆箱将是浪费
拳击计划立即将它们重新加载为java.lang.Integer。

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

相反,我们决定将Scala自己的拳击计划改为Java。该
之前的两个问题就消失了。一些与性能有关的
我们对Scala的拳击计划进行了优化(预计算
最常见数字的盒装形式)易于使用Java
拳击也。最后,使用Java拳击甚至比它快一点
我们自己的计划。

>“getMethod”的第二个参数是一个包含类型的数组
要查找的(结构定义的)方法的参数
选择名称重载时要获取的方法。这是
在这个过程中需要精确的静态类型的地方
翻译结构成员呼叫。通常,可利用的静态类型
对于方法的参数,结构类型提供
定义。在上面的示例中,参数类型“x”是已知的
是“Int”,允许查找它。

参数类型定义为抽象类型所在的抽象类型
在结构细化范围内定义是没有问题的
之一:
??def f(p:{def x [T](t:T):Int})= p.xInt
在这个例子中,我们知道任何传递给“f”的实例都是“p”
定义“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 [任意]({def x(t:任意)= 5},4)
查找第一个案例必须是“getMethod(”x“,
Array(int))“和第二个”getMethod(“x”,Array(Object))“和
没有办法知道在体内产生哪一个
“f”:“p.x(t)”。

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

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

但是现在,使用结构方法参数的抽象类型
类型是简单的禁止。

此致吉尔斯。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读