对象的Scala隐式转换
假设我有以下代码段:对象的Scala隐式转换,scala,implicit-conversion,scala-implicits,Scala,Implicit Conversion,Scala Implicits,假设我有以下代码段: 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 {
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"
}
我想将String
与Command
子体进行比较,而不进行显式转换。例如:
"sendMessage" == SendMessageCommand
implicit def string2Command(implicit s: String): Command = {
case "send_message" => SendMessageCommand
case _ => // some error thrown
}
问题1:在Scala中可能吗
问题2:我能否定义泛型隐式转换,将已知类型(如字符串)转换为超类类型(如我的例子中的Command
)
例如:
"sendMessage" == SendMessageCommand
implicit def string2Command(implicit s: String): Command = {
case "send_message" => SendMessageCommand
case _ => // some error thrown
}
另外,我知道这不是惯用的Scala,但找到正确的方法将是非常棒的。使用
==
无法做到这一点,但您可以定义自己的运算符:
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”)
至于第二个问题,我不确定我是否理解你的问题。。。“我可以定义隐式转换吗?”嗯,是的,你可以:)是的,这是可能的,但不能使用
=
,因为Scala只支持这些情况下的隐式转换:转换为预期类型,选择的接收器的转换,和隐式参数,因此隐式不适用于比较情况。相反,您必须在命令特征
中创建一个比较方法
,如下所示
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
方法。如果类型T
不是字符串,您可能也需要这样做。此外,您可以根据需要在convert方法
中实现自己的逻辑,而不是与toString
转换进行比较 多谢各位。问题2:我的意思是,我可以定义一个转换,该转换不会转换特定类型,而是转换其超级类型。如果问题不够清楚,我会更新。答案是“是的,你可以”。。。我还是不明白你为什么要问。您尝试过了吗,并得到了某种错误?一般来说,将这种通用隐式转换定义为convert
不是一个好主意。如果将其指定给String
s和Command
s,则也不需要重写Command#toString
。