2017-08-23 19 views
0

Scala的隐式转换,假设我有下面的代码片段:为对象

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 

问题1:Scala中可能吗?问题2:我可以定义通用隐式转换,将已知类型(如字符串)转换为超类类型(如我的情况下为Command)?

例如:

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

P.S.我知道这不是惯用的斯卡拉,但是找到正确的方法真是太棒了。

回答

1

是,其可能的,但不与==,因为只有这些情况下,Scala的支持隐式转换:转换到预期的类型,选择的接收器的转换,以及隐含参数因此隐式不适用于比较情况。相反,您必须在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比较在转换两个式实例,我不得不重写命令toString方法用于该用途的情况。如果不是字符串,也可能需要T。此外,您可以根据需要在convert method中实施您自己的逻辑,而不是与toString转换进行比较。

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")

至于第二个问题,我不知道我明白你问什么......“我可以定义的隐式转换?”嗯,是的,你可以:)

+0

谢谢。 Q2:我的意思是我可以定义一种转换,它不会转换为特定类型,而是转换为其超类型。如果不够清楚,我会更新这个问题。 –

+1

好吧,答案是“是的,你可以”......我仍然不明白为什么你需要问它。你尝试过,并得到某种错误? – Dima