0

假设我有以下代码片段:

import scala.language.implicitConversions

sealed trait Command {
  val typeName: String
}

object Command {

  implicit def command2String(implicit c: Command): String =
    c.typeName

}

case object SendMessageCommand extends Command {
  override val typeName: String = "send_message"
}

我想StringCommand没有显式转换的后代进行比较。例如:

"sendMessage" == SendMessageCommand

Q1:在 Scala 中可以吗?

Q2:我能否定义通用隐式转换,将已知类型(如 String)转换为超类类型(如Command我的情况)?

例如:

implicit def string2Command(implicit s: String): Command = {
  case "send_message" => SendMessageCommand
  case _ => // some error thrown
}

PS我知道它不是惯用的Scala,但找到正确的方法会很棒。

4

2 回答 2

1

是的,这是可能的,但不是==因为 Scala 仅支持以下情况的隐式转换:转换为预期类型、选择接收者的转换以及隐式参数,因此隐式不适用于比较情况。相反,您必须如下创建一个comparison methodCommand trait

  sealed trait Command {
    val typeName: String
    def isEqual(c: Command) = c.typeName == this.typeName
  }

  object SendMessageCommand extends Command {
    override val typeName: String = "send_message"
  }

  implicit def stringToCommand(s: String) = new Command {override val typeName: String = s}
  implicit def commandToString(c: Command) = c.typeName

  val strToCmdCompare = "send_message" isEqual SendMessageCommand
  val cmdToStrCompare = SendMessageCommand isEqual "send_message"

  println(strToCmdCompare)    //print true
  println(cmdToStrCompare)    //print true

现在,来到你的第二个问题,是的,可以定义一个通用的隐式转换来将任何给定类型转换为另一个类型实例。但是,据我了解您的情况,您有命令对象列表,并且您希望这些对象中的特定命令具有给定的字符串名称。为此,您必须拥有这些实例列表。

  sealed trait Command {
    val typeName: String
    //This is required for implicit conversion.
    override def toString: String = typeName
  }

  object SendMessageCommand extends Command {
    override val typeName: String = "send_message"
  }
  object AddMessageCommand extends Command {
    override val typeName: String = "add_message"
  }
  object UpdateMessageCommand extends Command {
    override val typeName: String = "update_message"
  }
  object DeleteMessageCommand extends Command {
    override val typeName: String = "delete_message"
  }

  //List of commands.
  implicit val cmds: List[Command] = List(SendMessageCommand, AddMessageCommand, UpdateMessageCommand, DeleteMessageCommand)

  //Convert given type T into type U.
  implicit def convert[T, U](s: T)(implicit list: List[U]): Option[U] = {
    list.find(_.toString == s.toString)
  }
  val res: Option[Command] = "add_message"
  println((res.getOrElse(null) == AddMessageCommand)) //print true

注意:当我通过将它们转换为 来比较转换中的两个类型实例时string,我必须toString为这个用例覆盖 Command 中的方法。T如果类型不是字符串,您可能也需要这样做。此外,您可以根据需要实现自己的逻辑,convert method而不是与toString转换进行比较。

于 2017-08-23T16:55:32.843 回答
0

你不能这样做==,但你可以定义自己的运算符:

 case class Foo(s: String) {
   def eq(x: Any) = x match {
     case Foo(str) => str == s
     case str: String => str == s
     cae _ => false
   } 
   def ==: (x: Any) = eq(s)
   def :== (x: Any) = eq(s)
 }

 "bar" ==: Foo("bar") // true
 Foo("bar") :== "bar" // true 
 Foo("bar") ==: Foo("bar") // true 

这是因为 scala 中的一个特殊技巧,使名称以冒号结尾的方法绑定到右侧而不是左侧:"bar" ==: Foo("bar")意味着Foo("bar").:==("bar"),而不是"bar".:==Foo("bar")

至于第二个问题,我不确定我是否理解您在问什么……“我可以定义隐式转换吗?” 嗯,是的,你可以:)

于 2017-08-23T14:29:10.363 回答