scala - 使用字符串插值进行模式匹配
问题描述
在以下使用 Scala 2.13.3 的示例中,第一个模式匹配,但第二个不匹配。
第 3 个模式再次匹配,而第 4 个不匹配(请注意,separator
第 4 个匹配表达式包含在反引号中,因此引用了之前定义的值)。
trait A
case object A extends A {
def unapply(a: String): Option[A] = if (a == "my_a") Some(A) else None
}
trait B
case object B extends B {
def unapply(b: String): Option[B] = if (b == "myB") Some(B) else None
}
val match1 = "myB_my_a" match {
case s"${B(b)}_${A(a)}" => Some((a,b))
case _ => None
} // Some((A,B))
val match2 = "my_a_myB" match {
case s"${A(a)}_${B(b)}" => Some((a,b))
case _ => None
} // None
val match3 = "my_a__myB" match {
case s"${A(a)}__${B(b)}" => Some((a,b))
case _ => None
} // Some((A,B))
val separator = "__"
val match4 = s"my_a${separator}myB" match {
case s"${A(a)}${`separator`}${B(b)}" => Some((a,b))
case _ => None
} // None
为什么只有第一个和第三个模式匹配?
对于第二个模式,是否有一个很好的匹配替代方案,即 a) 使用的unapply
方法A
和B
在哪里 b) 我们不知道这些方法接受什么字符串?
编辑 1:添加案例对象B
和另一个匹配示例。
编辑 2:另一个说明 jwvh 答案的例子:
val (a, b) = ("my_a", "myB")
val match5 = s"${a}_${b}" match {
case s"${`a`}_${`b`}" => Some((a, b)) // does not match
case s"${x}_${y}" => Some((x, y)) // matches: Some(("my", "a_myB"))
}
编辑 3:为了说明,与使用apply
and的案例类构造和提取不同unapply
,使用类似字符串插值的字符串的构造和提取不是(也不能是)反函数:
case class AB(a: String, b: String)
val id = (AB.apply _ tupled) andThen AB.unapply andThen (_.get)
val compare = id(("my_a", "myB")) == ("my_a", "myB") // true
val construct: (String, String) => String = (a,b) => s"${a}_${b}"
val extract: String => (String, String) = { case s"${a}_${b}" => (a,b) }
val id2 = (construct tupled) andThen extract
val compare2 = id2(("my_a","myB")) == ("my_a","myB") // false
解决方案
正如您自己的测试(在评论中提到)所展示的那样,插值器识别出匹配模式"${A(a)}_${B(b)}"
由下划线分隔的两部分组成_
。因此,我们会尽最大努力相应地拆分目标字符串。
第一部分,"my"
,被发送到A.unapply()
它失败的地方。"a_myB"
甚至没有尝试第二部分。
类似的事情发生在match4
. 该模式"${A(a)}${'separator'}${B(b)}"
有 3 个美元符号,因此有 3 个部分。但是,没有任何明确的字符来锚定模式,目标字符串被分成这 3 个部分。
""
""
"my_a__myB"
同样,第一部分失败了unapply()
,其他部分从未尝试过。
虽然您的Edit 3代码在技术上是正确的,但我并不觉得它非常有说服力。您已经简单地证明了(String,String)
=> AB(String,String)
=>(String,String)
是(或可以是)无损数据转换。(String,String)
=>不能这样说,String
它引入了一些歧义,即丢失了足以保证恢复原始数据的信息。这种损失是转换本身固有的,而不是用于实现它的工具(插值)。
case class
和String
插值都使用apply()
/unapply()
在引擎盖下的事实让我觉得无关紧要。
推荐阅读
- angular - 带有角度6的浏览器请求的Spring security jwt不起作用但邮递员请求有效
- java - Sequence Generator without @Id annotation in java with hibernate in Postgres within a range
- azure-devops - 如何解决工件的发布管道部署问题?
- eclipse - 为什么 Eclipse Scala 项目找不到 Scala?
- java - 更改密码以在 Apache Ignite 中连接服务器
- c# - 使用 bind=true 将消息发送到优先级队列
- java - 在模块类中发现重复的类
- javascript - 使用“localStorage.setItem”Internet Explorer
- slack - 在直接消息松弛通道中获取用户的用户 ID
- java - 如何在 try 和 catch 块的 return 语句之后打印 finally 块中的语句?