变形提取器

提取器行为可用于从其输入中派生任意值。这在你希望能够在转换成功的情况下对转换结果执行操作的情况下非常有用。

以 Windows 环境中可用的各种用户名格式为例 :

object UserPrincipalName {
  def unapply(str: String): Option[(String, String)] = str.split('@') match {
    case Array(u, d) if u.length > 0 && d.length > 0 => Some((u, d))
    case _ => None
  }        
}

object DownLevelLogonName {
  def unapply(str: String): Option[(String, String)] = str.split('\\') match {
    case Array(d, u) if u.length > 0 && d.length > 0 => Some((d, u))
    case _ => None
  }
}

def getDomain(str: String): Option[String] = str match {
  case UserPrincipalName(_, domain) => Some(domain)
  case DownLevelLogonName(domain, _) => Some(domain)
  case _ => None
}

事实上,通过扩展它可以匹配的类型,可以创建一个展示这两种行为的提取器:

object UserPrincipalName {
  def unapply(obj: Any): Option[(String, String)] = obj match {
    case upn: UserPrincipalName => Some((upn.username, upn.domain))
    case str: String => str.split('@') match {
      case Array(u, d) if u.length > 0 && d.length > 0 => Some((u, d))
      case _ => None
    }
    case _ => None
  }        
}

一般来说,提取器只是一种方便的 Option 模式重构,适用于名称如 tryParse 的方法:

UserPrincipalName.unapply("user@domain") match {
  case Some((u, d)) => ???
  case None => ???
}