Scala列出了存在类型:`map {case t => …}`works,`map {t =&
假设我们已经定义了一个存在类型:
type T = (X => X,X) forSome { type X } 然后定义List [T]类型的列表: val list = List[T]( ((x: Int) => x * x,42),((_: String).toUpperCase,"foo") ) 众所周知[1],[2]以下尝试映射不起作用: list.map{ x => x._1(x._2) } 但是,为什么以下工作呢?: list.map{ case x => x._1(x._2) } 请注意,两个链接问题的答案都假定模式匹配中需要一个类型变量,但它也可以在没有类型变量的情况下工作.问题的重点在于为什么{case x => ……}工作? 解决方法
(我自己试图回答这个问题;应该不是太错了,但也许有点肤浅.)
首先,观察一下 list.map{ x => x._1(x._2) } list.map{ case x => x._1(x._2) } 与…基本相同 list map f1 list map f2 同 val f1: T => Any = t => t._1(t._2) val f2: T => Any = _ match { case q => q._1(q._2) } 实际上,f1的编译失败了,而f2成功了. 我们可以看到为什么f1的编译必须失败: > t是类型(X => X,X)的某些{类型X} 因此,f1的编译应该失败,它确实会失败. 要了解为什么f2成功编译,可以查看类型检查器的输出.如果我们将其保存为someFile.scala: class O { type T = (X => X,X) forSome { type X } def f2: T => Any = t => t match { case q => q._1(q._2) } def f2_explicit_func_arg: T => Any = t => t match { case q => { val f = q._1 val x = q._2 f(x) } } } 然后使用生成typechecker的输出 $scalac -Xprint:typer someFile.scala 我们获得了基本上(删除了一些噪音): class O extends scala.AnyRef { type T = (X => X,X) forSome { type X }; def f2: O.this.T => Any = ((t: O.this.T) => t match { case (q @ _) => q._1.apply(q._2) }); def f2_explicit_func_arg: O.this.T => Any = ((t: O.this.T) => t match { case (q @ _) => { val f: X => X = q._1; val x: X = q._2; f.apply(x) } }) } 第二个f2_explicit_func_arg版本(相当于f2)比较短的原始f2版本更具启发性.在f2_explicit_func_arg的desugared和类型检查代码中,我们看到类型X奇迹般地再次出现,并且类型检查器确实推断: f: X => X x: X 所以f(x)确实有效. 在使用显式命名的类型变量的更明显的解决方法中,我们手动执行编译器在这种情况下为我们做的事情. 我们也可以写: type TypeCons[X] = (X => X,X) list.map{ case t: TypeCons[x] => t._1(t._2) } 甚至更明确地: list.map{ case t: TypeCons[x] => { val func: x => x = t._1 val arg: x = t._2 func(arg) }} 并且这两个版本的编译原因与f2非常相似. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |