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

Scala TraversableOnce和toSet

发布时间:2020-12-16 21:32:56 所属栏目:安全 来源:网络整理
导读:在 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( _ + " "
在 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中可以看到的那样(空的参数列表将被视为gen.mkTuple的单位文字):

/* 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

(编辑:李大同)

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

    推荐文章
      热点阅读