【问题标题】:Is it possible to use implicit conversions for parameters to extractors (unapply) in Scala?是否可以在 Scala 中对提取器(不应用)的参数使用隐式转换?
【发布时间】:2009-12-01 03:26:00
【问题描述】:

我创建了一个名为 CaseInsensitive 的类,它包装了一个字符串(请参阅Implementing a string class that does case insensitive comparisions in Scala)。

我创建了一个 case 类,它有一个 CaseInsensitive 类型的成员变量,所以它有一个默认的 unapply 方法,该方法提取一个 CaseInsensitive 类型的变量,但我希望像这样使用它:

case class PropertyKey( val name : CaseInsensitive )

val foo = new PropertyKey("foo")
val result = foo match {
  case PropertyKey("foo") => true
  case _ => false
}

此代码编译失败:(在提取器行,而不是构造器行)

type mismatch;
 found   : java.lang.String("foo")
 required: com.acme.CaseInsensitive 

但我认为我从 String 到 CaseInsensitive 的隐式转换可以编译,而不是我必须输入更详细的内容:

case class PropertyKey( val name : CaseInsensitive )

val foo = new PropertyKey("foo")
val result = foo match {
  case PropertyKey(CaseInsensitive("foo")) => true
  case _ => false
}

这里是CaseInsensitive的实现:

/** Used to enable us to easily index objects by string, case insensitive
 * 
 * Note: this class preserve the case of your string!
 */
case class CaseInsensitive ( val _s : String ) extends Proxy {
  require( _s != null)

  val self = _s.toLowerCase
  override def toString = _s

  def i = this // convenience implicit conversion
}

object CaseInsensitive {
  implicit def CaseInsensitive2String(c : CaseInsensitive) = if ( c == null ) null else c._s
  implicit def StringToCaseInsensitive(s : String) = CaseInsensitive(s)

  def fromString( s : String ) = s match {
    case null => None
    case _ => Some(CaseInsensitive(s))
  }
}

【问题讨论】:

  • 您不能只实施和使用 CI 比较吗?我相信 CI 字符串是一个格式错误的概念,区分大小写是操作的属性,而不是数据的属性。如果将 CSstring 与 CIstring 进行比较会发生什么?这两个是关于 C++ 的,但尤其是。 Austern 的文章有一些相关的想法。 gotw.ca/gotw/029.htmlafstern.org/matt/col2_new.pdf
  • 我将对象存储在 HashMap[T] 和其他数据结构中,我将如何“仅实现 CI 比较”?无论如何,这个问题并不特定于此类 CaseInsensitive,而是关于一般的 Scala 提取器。
  • 感谢 Austern 文章的链接,只是想弄清楚如何在 Scala 中应用他的想法。
  • 提取器“解构”数据结构。您需要一个隐含的 from CaseInsensitive to String 才能使匹配生效。并不是说我认为它会起作用,而只是为了纠正误解。
  • @Daniel:我对两个方向都有一个隐含的。我认为它可以去任何一种方式,不是吗?例如。将 PropertyKey 解构为不区分大小写,然后将其隐式转换为字符串,然后将其与提供的字符串进行比较。或者,将 PropertyKey 解构为 CaseInsensitive,然后将提供的字符串隐式转换为 CaseInsensitive,然后进行比较。

标签: scala extractor unapply


【解决方案1】:

您总是可以定义一个方便的提取器并导入它(随意使用更短的名称):

object PropertyKeyCI {
  def unapply(p: PropertyKey): Option[String] = Some(p.name.self)
}

那么,提取是:

  val foo = new PropertyKey("foo")
  val result = foo match {
    case PropertyKeyCI("foo") => true
    case _ => false
  }

(错误语义警报)

虽然请注意,这对于 PropertyKeyCI("Foo") 将匹配为 false,因为您的“CaseInsensitive”类实际上是一个“LowerCase”类。我这样说是因为我很难想象 unapply() 方法的期望行为是什么。从您的案例类默认值中,您将返回原始(未小写)字符串的 Option[String],这会产生这种不直观的行为:

  // result == false !!!!
  val foo = new CaseInsensitive("Foo")
  val result = foo match {
    case CaseInsensitive("foo") => true
    case _ => false
  }
  val CaseInsensitive(s) = "aBcDeF"
  assertFalse(s == "abcdef")

哇……扔了。只需使用 DOS。

【讨论】:

  • 谢谢米奇,是的,我探索了那条路线,只是没有那么好/干净。如果我可以在同一个对象上使用两个 unapply 方法,那就太好了!
  • 您确定 CaseInsensitive 是小写类吗?它保留现有大小写,并将字符串的小写版本用于 hashCode 和 equals。
  • 我想尝试以这种方式进行模式匹配让我这样想。将编辑答案以澄清(使用代码)。
  • +1 在同一个对象上有多个 unapply 方法。我不知道我尝试了多少次,编译器一直拒绝我。
猜你喜欢
  • 2019-01-20
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多