是否可以在 Scala 中对提取器(不应用)的参数使用隐式转换?

是否可以在 Scala 中对提取器(不应用)的参数使用隐式转换?

问题描述:

我创建了一个名为 CaseInsensitive 的类,它包含一个字符串(参见 实现一个字符串类,在 Scala 中进行不区分大小写的比较).

I have created a class called CaseInsensitive which wraps a string (see Implementing a string class that does case insensitive comparisions in Scala).

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

I've created a case class which has a member variable of type CaseInsensitive, so it gets a default unapply method, which extracts a variable of type CaseInsensitive, but I was hoping to use it like this:

case class PropertyKey( val name : CaseInsensitive )

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

此代码无法编译:(在提取器行,而不是构造函数行)

This code fails to compile: (on the extractor line, not the constructor line)

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

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

But I thought my implicit conversions from String to CaseInsensitive would enable this to compile, rather than me having to type the more verbose:

case class PropertyKey( val name : CaseInsensitive )

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

这里是 CaseInsensitive 的实现:

Here is the implementation of 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))
  }
}

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

You could always define a convenience extractor and import it (feel free to use a shorter name):

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],这给出了这种不直观的行为:


(Bad Semantics Alert)

Although note that this would match as false for PropertyKeyCI("Foo"), because your "CaseInsensitive" class is really a "LowerCase" class. I say this because it is hard for me to imagine what the desired behavior would be for the unapply() method otherwise. From your case class default, you are returning an Option[String] of the original (unlowercased) string, which gives this unintuitive behavior:

  // 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吧.

Awwww.... toss it. Just use DOS.