为什么我可以在模式匹配中将 :: 运算符与 Seq 一起使用,但在其他地方却不能

2024-03-05

所以我对 Scala 中 Seq 的这种行为感到非常困惑。

使用模式匹配时,我可以使用:: or +:运算符,它们似乎可以互换

val s=Seq(1,2,3)
s match{
case x :: l => ...

但是当我尝试使用时::在不同的情况下像这样:

val s=1::Seq(2,3)

我收到"value :: is not a member of Seq[Int]"信息。我明白我应该使用+= and =+与 Seq 的运算符,但为什么::只适用于模式匹配场景?


:: is for Lists,事实上Seq.apply目前将为您提供List:

scala> val s = Seq(1,2,3)
s: Seq[Int] = List(1, 2, 3)

所以值的类型s is Seq[Int],但它指向的对象是类型List[Int]。没关系,因为List延伸Seq。这当然会匹配涉及的模式::因为它实际上是一个List:

scala> s match { case x :: xs => x }
res2: Int = 1

但表达的类型Seq(1,2,3) is not List[Int] but Seq[Int]——即使实际的物体确实是一个List。所以以下失败是因为Seq没有定义一个:: method:

scala> val s = 1 :: Seq(2,3)
<console>:7: error: value :: is not a member of Seq[Int]
       val s = 1 :: Seq(2,3)

你必须使用该方法Seq反而:

scala> val s = 1 +: Seq(2,3)
s: Seq[Int] = List(1, 2, 3)

造成您困惑的关键是,当您对类似值调用方法时s,可用的方法集完全取决于值的static类型,而模式匹配检查匹配的对象是否属于类::.

为了展示这一点,让我们编译一些示例代码并使用javap查看字节码;的前几条指令first方法检查参数是否属于类::(而不是其他一些扩展类Seq) 并投射到它:

NS% cat Test.scala
object Test {
  def first(xs: Seq[Int]) = xs match { case x :: xs => x }
}

NS% javap -c Test\$.class
Compiled from "Test.scala"
public final class Test$ {
  public static final Test$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class Test$
       3: invokespecial #12                 // Method "<init>":()V
       6: return

  public int first(scala.collection.Seq<java.lang.Object>);
    Code:
       0: aload_1
       1: astore_2
       2: aload_2
       3: instanceof    #16                 // class scala/collection/immutable/$colon$colon
       6: ifeq          30
       9: aload_2
      10: checkcast     #16                 // class scala/collection/immutable/$colon$colon
      13: astore_3
      14: aload_3
      15: invokevirtual #20                 // Method scala/collection/immutable/$colon$colon.head:()Ljava/lang/Object;
      18: invokestatic  #26                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
      21: istore        4
      23: iload         4
      25: istore        5
      27: iload         5
      29: ireturn
      30: new           #28                 // class scala/MatchError
      33: dup
      34: aload_2
      35: invokespecial #31                 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
      38: athrow

最后,你可能会问为什么 Scala 人不做::等效方法(前置一个元素)Seq。如果他们有的话1 :: Seq(2,3)会工作。

But for Seq他们确实需要一个pair运算符,一个用于前置(该运算符必须以冒号结尾,以便它是右关联的),一个用于附加。您想避免将元素附加到List因为你必须遍历现有的元素才能做到这一点,但对于Seq一般而言——例如追加对于一个来说是相当有效的Vector。所以他们选择了+:用于前置和:+用于追加。

当然,你可以问为什么他们不使用+: for List匹配Seq。我不知道完整的答案。我确实知道::来自具有列表结构的其他语言,因此部分答案可能是与既定约定的一致性。也许他们没有意识到他们需要一对匹配的运算符来作为超类型List直到为时已晚——不确定。有谁知道这里的历史吗?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我可以在模式匹配中将 :: 运算符与 Seq 一起使用,但在其他地方却不能 的相关文章

随机推荐

  • 将表单身份验证添加到 ASP.Net 项目会导致 401.2 未经授权?

    我正在尝试将表单身份验证插入到最初使用 VS 2013 和 ASP Net 4 0 使用无身份验证模板创建的 ASP Net 项目中 我已遵循 MSDN 上的建议 并将其添加到 system web 下的 Web Config 中
  • 添加资源文件到xcode

    我正在尝试将一些新的资源文件添加到由另一个人在另一台 Mac 上构建的项目中 我认为该项目有前人的规定 使用右键单击 gt 将文件添加到 MyProject 不会提供预期的结果 编译项目后 添加的文件在应用程序中不可见 如何在我的项目中添加
  • 最新的 Jersey 示例不起作用

    我已经安装了最新版本的球衣 捆绑版本 2 13 0 以及该版本的示例 然后我尝试了 用于测试 Restful 服务 examples helloworld pure jax rs src main java org glassfish je
  • JavaScript 加载图像的进度

    JS 有没有办法在加载图像时获取加载图像的进度 我想使用HTML5新的Progress标签来显示加载图像的进度 我希望有这样的东西 var someImage new Image someImage onloadprogress funct
  • MongoDB - 大量 MongoCleaner 线程

    不知何故 我的 java 应用程序与 mongodb 通信最终产生了大量名为 MongoCleanerXXX 的停放 睡眠 线程 我认为它来自驱动程序 其数量约为 600 显然数据库存在一些连接问题 在 mongod 重新启动一段时间后确实
  • 我的 httpd.conf 是空的

    我最近在 ubuntu 上安装了 apache2 但我有一个问题 我的 httpd conf 是空的 有人能给我一份 ubuntu 上 apache2 的 httpd conf 的干净副本吗 谢谢 编辑 我看到了你的答案 但在 wampse
  • 如何让dput删除多余的数据?

    我想要一个 SO 问题的最小可重现代码 我一直在使用dput droplevels head df 50 然而 df大约有 4k 条记录 看起来像dput正在为每个人打印一些东西 我需要在问题中显示两个不同的 df 所以不会让我超过 30
  • 打字稿中具有数据水合/脱水的类

    我想分享 React TS 前端和 Node TS 后端之间的 TS 类或接口 问题是 TS 类型在编译时被剥离 所以当我想将类实例转换为 JSON 时我无法使用它们 我想知道是否有任何解决方案可以在静态文件中描述我的对象 生成 TS 类
  • 在 .Net 2.0 中对 IList 进行排序的最佳方法是什么?

    我有一个IList
  • 当调试器设置为 LLDB 时,Xcode 4 挂起附加到(应用程序名称)

    当我在模拟器中运行应用程序时 Xcode 挂在 附加到 应用程序名称 上 但这仅在调试器设置为 LLDB 时发生 当调试器设置为 GDB 时 应用程序运行良好 产品 gt 编辑方案 gt 运行 gt 调试器 如何修复此问题以使用 LLDB
  • C static 关键字与 C++ 私有作用域?

    本地翻译单元的 C 等效项是什么staticC 中的函数 例如有以下内容bar c static void bar 在C 中 这会被写成私有成员函数吗 class foo void bar void foo bar 私有成员函数隐式引入了t
  • 用例图包括

    我有一个关于用例图的问题 如图所示 用户可以输入或更新他的姓名和问题 正如您所看到的 用户在第一次输入信息时需要输入姓名和问题 因此包括在内 但是 如果他希望更新他的信息 图表是否表明他必须修改名称和问题 因为它们包含在内 例如 如果他拼错
  • Economist.com 如何实施其粘性标题? jQuery?

    如果您访问 经济学人 网站上的一篇文章 例如 http www economist com node 17629757 http www economist com node 17629757 当您向下滚动页面超过某个点 使用 PAGEDO
  • 如何禁用 <> 的自动关闭而不禁用其他括号 () {}?

    我对自动完成的功能感到恼火 lt gt Rust 的 VSCode 中的括号 虽然它在指定泛型类型时可能很有用 但当它为我的小于运算符自动完成 gt 时 它确实让我烦恼 我知道我可以完全禁用自动关闭括号 但是有没有办法指定其中哪些应该被视为
  • 如何使用 matplotlib 在 python 中绘制 3D 密度图

    我有一个 x y z 蛋白质位置的大型数据集 并且想将高占用率区域绘制为热图 理想情况下 输出应该类似于下面的体积可视化 但我不确定如何使用 matplotlib 实现这一点 我最初的想法是将我的位置显示为 3D 散点图 并通过 KDE 对
  • 让 Flex 容器采用内容的宽度,而不是宽度 100%

    在下面的示例中 我有一个具有以下样式的按钮 button flexbox approach other button styles display flex justify content center align items center
  • 如何使用 Windows api 更改时区设置

    我需要在我的应用程序中通过 API 更改 DST 和时区 我在以下链接末尾修改并复制了 GetTimeZoneInformation 用法的示例并运行了它 http msdn microsoft com en us library wind
  • 来自 gstatic 的 PhantomJS JavaScript 错误,但浏览器中没有错误

    我最近通过 PhantomJS 测试套件运行我们的网站 遇到了无法在浏览器中手动重现的 JavaScript 错误 这些错误是在 Google 地图 api 中发现的 Capybara 返回的文本如下 TypeError Unable to
  • 如何连接多个queryDSL表

    我有一些表 我想使用 queryDSL 连接获取结果 但没有找到任何使用 queryDSL 进行多个连接的示例 我有这些表 账户表 accountId PK 电子邮件 密码 account profile 表 accountId PK fk
  • 为什么我可以在模式匹配中将 :: 运算符与 Seq 一起使用,但在其他地方却不能

    所以我对 Scala 中 Seq 的这种行为感到非常困惑 使用模式匹配时 我可以使用 or 运算符 它们似乎可以互换 val s Seq 1 2 3 s match case x l gt 但是当我尝试使用时 在不同的情况下像这样 val