Scala TraversableOnce和toSet
在
Scala中,为什么在使用TraversableOnce的toSet功能时会发生以下情况?
如果您使用以下代码创建工具(IntelliJ),您将获得以下输出(注意:使用Scala 2.10.2): val maps = List(List(1,2),List(3,4),List(5,6,7),List(8),List()) maps.flatMap( _.map( _ + " " ) ) maps.flatMap( _.map( _ + " " ) ).toSet maps.flatMap( _.map( _ + " " ) ).toSet() 即res4产生一个布尔值 > maps: List[List[Int]] = List(List(1,List()) > res2: List[String] = List("1 ","2 ","3 ","4 ","5 ","6 ","7 ","8 ") > res3: scala.collection.immutable.Set[String] = Set("3 ","8 ","1 ","7 ") > res4: Boolean = false 不用说我被困惑了很长时间,直到我注意到Set不使用括号在实现,但为什么布尔? 解决方法
正如您和其他人已经注意到,toSet不提供参数列表.因此,使用括号调用它将总是导致编译错误,除非编译器找到一个apply方法,该方法需要一个参数,就像在示例中那样:
scala> List(1).toSet() res2: Boolean = false scala> List(1).toSet.apply() res3: Boolean = false scalac具有称为“适应参数列表”的功能,这可以用-Xlint显示: scala> List(1).toSet() <console>:8: warning: Adapting argument list by inserting (): this is unlikely to be what you want. signature: GenSetLike.apply(elem: A): Boolean given arguments: <none> after adaptation: GenSetLike((): Unit) List(1).toSet() ^ res7: Boolean = false scalac尝试将参数包装成一个元组,就像sources中可以看到的那样(空的参数列表将被视为 /* Try packing all arguments into a Tuple and apply `fun` * to that. This is the last thing which is tried (after * default arguments) */ def tryTupleApply: Tree = ( if (eligibleForTupleConversion(paramTypes,argslen) && !phase.erasedTypes) { val tupleArgs = List(atPos(tree.pos.makeTransparent)(gen.mkTuple(args))) // expected one argument,but got 0 or >1 ==> try applying to tuple // the inner "doTypedApply" does "extractUndetparams" => restore when it fails val savedUndetparams = context.undetparams silent(_.doTypedApply(tree,fun,tupleArgs,mode,pt)) map { t => // Depending on user options,may warn or error here if // a Unit or tuple was inserted. val keepTree = ( !mode.typingExprNotFun || t.symbol == null || checkValidAdaptation(t,args) ) if (keepTree) t else EmptyTree } orElse { _ => context.undetparams = savedUndetparams ; EmptyTree } } else EmptyTree ) 哪个btw是not mentioned in the spec的一个功能.明确添加括号会让警告消失: scala> List(1).toSet(()) res8: Boolean = false 现在还有一个问题是为什么上面的代码不会产生一个编译错误,因为列表是List [Int]的类型,而Set的apply方法具有类型签名apply(A):Boolean,因此期望Int我们的情况.其原因是very well known problem和toSet [B>:A]的类型签名的结果:Set [B].类型签名表示下限,这意味着Int的任何超类型都可以作为参数传递. 因为在我们的例子中,Unit被指定为参数的类型,编译器必须搜索与toSet的类型签名相匹配的Unit和Int的公共超类型.并且因为有这样一个类型,即AnyVal,编译器会推断出这个类型,并且前进,而不会出现一个错误: scala> List(1).toSet[AnyVal](()) res9: Boolean = false (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |