简体   繁体   English

Scala - 这个 map + case 语法是什么?

[英]Scala - what is this map + case syntax?

I can't seem to find further information on this language feature where you can put a case inside a map like this:我似乎无法找到有关此语言功能的更多信息,您可以在其中将case放入map ,如下所示:

   val sVersion = CrossVersion.partialVersion(scalaVersion)
      .map { case (major:Long, minor: Long) => s"_$major.$minor" } getOrElse ""

I've been starting to use this syntax, but what is it called and where can I find more information on it?我已经开始使用这种语法,但它叫什么,我在哪里可以找到更多关于它的信息?

I've been starting to use this syntax, but what is it called […]我已经开始使用这种语法,但它叫什么 […]

It is officially called a Pattern Matching Anonymous Function .它的官方名称是匿名模式匹配 Function The Scala community also sometimes refers to it as a Partial Function Literal . Scala 社区有时也将其称为Partial Function Literal

[…] and where can I find more information on it? [...] 我在哪里可以找到更多信息?

The ultimate source of truth for everything in the Scala Programming Language is the Scala Language Specification (aka SLS ) . Scala 编程语言中所有内容的最终真实来源是Scala 语言规范(又名SLS You will note that I have linked to version 2.13 of the spec – unfortunately, a single consolidated spec for Scala 3 has not been published yet.您会注意到我已经链接到规范的 2.13 版——不幸的是,尚未发布 Scala 3 的单一综合规范。

See Scala Language Specification 8.5 Pattern Matching Anonymous Functions for all the gory details.有关所有详细信息,请参阅Scala 语言规范 8.5模式匹配匿名函数 Simply put, the expression简单地说,表达式

{
  case p1 => e1
  case p2 => e2
  // …
  case pn => en
}

is equivalent to相当于

(x1: S1, x2: S2, /* … */, xn: Sn) => (x1, x2, /* … */, xn) match {
  case p1 => e1
  case p2 => e2
  // …
  case pn => en
}

provided that the result type is SAM-convertible to FunctionN[S1, S2, /* … */, Sn, R] , or as a special casePartialFunction1[S1, R] (which is where the name Partial Function Literal comes from.)前提是结果类型可通过SAM 转换FunctionN[S1, S2, /* … */, Sn, R] ,或者作为特殊情况PartialFunction1[S1, R] (这是名称Partial Function Literal的来源。 )

In Scala 3, there is a new feature which can make this code even more concise: For a very long time, the Scala Designers wanted to unify Tuples and Argument Lists .在 Scala 3 中,有一个新特性可以使这段代码更加简洁: 很长一段时间以来, Scala 的设计者都希望统一TuplesArgument Lists In other words, they wanted to make it so that methods in Scala only ever take one argument, and that argument is a tuple.换句话说,他们想让 Scala 中的方法只接受一个参数,而这个参数是一个元组。 Unfortunately, it turned out that a) this massively breaks backwards-compatibility and b) massively breaks platform interoperability.不幸的是,事实证明 a) 这极大地破坏了向后兼容性和 b) 极大地破坏了平台互操作性。

Now, Scala 3 was an opportunity to ignore problem a), but you cannot ignore problem b) since one of the major design goals of Scala is to have seamless, tight, good, performant integration with the underlying host platform (eg .NET in the case of the now-abandoned Scala.NET, the ECMASCript / HTML5 / DOM / WebAPI platform in the case of Scala.js, the native Operating System in the case of Scala-native, or the Java platform (JRE, JDK, JVM, J2SE, J2EE, Java, Kotlin, Clojure, etc.) in the case of Scala-JVM).现在,Scala 3 是一个忽略问题 a) 的机会,但您不能忽略问题 b),因为 Scala 的主要设计目标之一是与底层主机平台(例如 .NET 在现在废弃的 Scala.NET,ECMASCript / HTML5 / DOM / WebAPI 平台,Scala.js,本机操作系统,Scala-native,或 Java 平台(JRE,JDK,JVM, J2SE、J2EE、Java、Kotlin、Clojure 等)在 Scala-JVM 的情况下)。

However, the Scala designers managed to find a compromise, where arguments and tuples are not the same thing, but parameters can be easily converted to tuples and tuples can be easily converted to arguments.然而,Scala 的设计者设法找到了折衷方案,其中 arguments 和元组不是一回事,但参数可以很容易地转换为元组,而元组可以很容易地转换为 arguments。

This is called Parameter Untupling , and it basically means that a function of type FunctionN[S1, S2, /* … */, Sn, R] can be automatically converted to a function of type Function1[(S1, S2, /* … */, Sn), R] which is syntactic sugar for Function1[TupleN[S1, S2, /* … */, Sn], R] .这称为Parameter Untupling ,它基本上意味着类型FunctionN[S1, S2, /* … */, Sn, R]的 function 可以自动转换为类型Function1[(S1, S2, /* … */, Sn), R]Function1[TupleN[S1, S2, /* … */, Sn], R]的语法糖。

Simply put,简单的说,

(p1: S1, p2: S2, /* … */, pn: Sn) => e: R

can automatically be converted to可以自动转换为

(x: (S1, S2, /* … */, Sn)) => {
  val p1: S1 = x._1
  val p2: S2 = x._2
  // …
  val pn: Sn = x._n

  e
}

With this, your code would look like:这样,您的代码将如下所示:

val sVersion = CrossVersion.partialVersion(scalaVersion)
  .map { (major: Long, minor: Long) => s"_$major.$minor" } getOrElse ""

Note: unfortunately, there is no comprehensive specification of Scala 3 yet.注意:不幸的是,目前还没有 Scala 3 的全面规范。 There is a partial Language Reference , which however only describes differences to Scala 2. So, you typically have to bounce back and forth between the SLS and the Scala 3 docs.有部分语言参考,但仅描述了与 Scala 2 的差异。因此,您通常必须在 SLS 和 Scala 3 文档之间来回切换。

In Scala 2, it's called pattern-matching decomposition在Scala 2中,称为pattern-matching decomposition

see: https://docs.scala-lang.org/scala3/reference/other-new-features/parameter-untupling.html请参阅: https://docs.scala-lang.org/scala3/reference/other-new-features/parameter-untupling.html

in Scala 3, you can just在Scala 3,你可以

val sVersion = CrossVersion.partialVersion(scalaVersion)
      .map { (major:Long, minor: Long) => s"_$major.$minor" } getOrElse ""

This is usually called "destructuring" or "destructuring bind" (ex: in Clojure https://clojure.org/guides/destructuring ).这通常称为“解构”或“解构绑定”(例如:在 Clojure https://clojure.org/guides/destructuring 中)。 Scala uses pattern matching to achieve this. Scala 使用模式匹配来实现这一点。

In your example, you use shortened pattern matching to destructure the Option which contains the version.在您的示例中,您使用缩短的模式匹配来解构包含版本的Option You could also skip the explicit Long type declaration.您也可以跳过显式Long类型声明。

Good reads on this topic:关于这个主题的好读物:

https://www.oreilly.com/library/view/programming-scala-2nd/9781491950135/ch04.html https://docs.scala-lang.org/cheatsheets/index.html https://www.oreilly.com/library/view/programming-scala-2nd/9781491950135/ch04.html https://docs.scala-lang.org/cheatsheets/index.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM