是否可以在Scala中使用隐式转换参数来提取器(unapply)?

时间:2009-11-30 16:16:52

标签: scala extractor unapply

我创建了一个名为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))
  }
}

1 个答案:

答案 0 :(得分:4)

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

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
  }

(Bad Semantics Alert)

虽然请注意,这与PropertyKeyCI(“Foo”)匹配为false,因为您的“CaseInsensitive”类实际上是“LowerCase”类。我这样说是因为我很难想象unapply()方法会有什么样的行为。从您的case类默认情况下,您将返回原始(未降级)字符串的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")

Awwww ....折腾它。只需使用DOS。