对象的 Scala 隐式转换
Scala implicit conversion for object
假设我有以下代码片段:
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
Q1:在Scala中可以吗?
问题 2:我可以定义泛型隐式转换,将已知类型(例如 String)转换为超级 class 类型(例如我的 Command
类型)吗?
例如:
implicit def string2Command(implicit s: String): Command = {
case "send_message" => SendMessageCommand
case _ => // some error thrown
}
P.S。我知道这不是惯用的 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")
关于第二个问题,我不确定我是否明白你在问什么...... "Can I define an implicit conversion?"嗯,是的,你可以:)
是的,有可能,但 ==
不行,因为 Scala 仅支持这些情况的隐式转换:转换为预期类型、选择接收者的转换和隐式参数 因此 implicit 不适用于比较案例。相反,您必须在 Command trait
中创建一个 comparison method
,如下所示。
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
来比较转换中的两个类型实例,因此我必须为此用例重写 Command 中的 toString
方法。如果类型 T
不是字符串,您可能也需要这样做。此外,您可以根据需要在 convert method
中实现自己的逻辑,而不是与 toString
转换进行比较。
假设我有以下代码片段:
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
Q1:在Scala中可以吗?
问题 2:我可以定义泛型隐式转换,将已知类型(例如 String)转换为超级 class 类型(例如我的 Command
类型)吗?
例如:
implicit def string2Command(implicit s: String): Command = {
case "send_message" => SendMessageCommand
case _ => // some error thrown
}
P.S。我知道这不是惯用的 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")
关于第二个问题,我不确定我是否明白你在问什么...... "Can I define an implicit conversion?"嗯,是的,你可以:)
是的,有可能,但 ==
不行,因为 Scala 仅支持这些情况的隐式转换:转换为预期类型、选择接收者的转换和隐式参数 因此 implicit 不适用于比较案例。相反,您必须在 Command trait
中创建一个 comparison method
,如下所示。
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
来比较转换中的两个类型实例,因此我必须为此用例重写 Command 中的 toString
方法。如果类型 T
不是字符串,您可能也需要这样做。此外,您可以根据需要在 convert method
中实现自己的逻辑,而不是与 toString
转换进行比较。