scala:使用隐式为方法的每个参数支持两种不同的类型?
假设我有一个接受大量参数的方法,每个参数可以是字符串或Seq[String]。在该方法中,我希望每个参数的值如果是字符串,则仅为该值;如果是Seq[String],则为Seq上的mkString“”。我知道这里可以使用Left/Right,但我不希望调用方必须包装任何参数 我已经使用implicits强制arg为String或Seq[String],但我不知道如何让arg根据具体情况将其自身还原为String,或者作为标识,或者作为mkString。理想的代码可能如下所示:scala:使用隐式为方法的每个参数支持两种不同的类型?,scala,Scala,假设我有一个接受大量参数的方法,每个参数可以是字符串或Seq[String]。在该方法中,我希望每个参数的值如果是字符串,则仅为该值;如果是Seq[String],则为Seq上的mkString“”。我知道这里可以使用Left/Right,但我不希望调用方必须包装任何参数 我已经使用implicits强制arg为String或Seq[String],但我不知道如何让arg根据具体情况将其自身还原为String,或者作为标识,或者作为mkString。理想的代码可能如下所示: trait StrO
trait StrOrSeqStr[A]
implicit object Str extends StrOrSeqStr[String]
implicit object SeqStr extends StrOrSeqStr[Seq[String]]
def f[A, B](a: A, b: B)(implicit a: StrOrSeqStr[A], implicit b: StrOrSeqStr[B]) {
val aIn: String = a
val bIn: String = b // converts strings to themselves, seq strings as _ mkString " "
}
// both should work
f(Seq("1"), "2")
f("1", Seq("2", "3"))
有什么建议吗?谢谢 如果我错了,请纠正我,但据我所知,您只需要隐式地将
String
转换为Seq[String]
。这个简单的隐式转换应该可以做到这一点:
implicit def stringToSeqString(s: String) = Seq(s)
def f(a: Seq[String], b: Seq[String]) {
val (aIn, bIn) = (a mkString " ", b mkString " ")
// ...
}
f(Seq("1"), "2")
f("1", Seq("2", "3"))
如果我错了,请纠正我,但据我所知,您只需要隐式地将
String
转换为Seq[String]
。这个简单的隐式转换应该可以做到这一点:
implicit def stringToSeqString(s: String) = Seq(s)
def f(a: Seq[String], b: Seq[String]) {
val (aIn, bIn) = (a mkString " ", b mkString " ")
// ...
}
f(Seq("1"), "2")
f("1", Seq("2", "3"))
据我所知,您试图使用上下文边界来赋予函数
f
一些可以被视为String
或可以转换为它的内容。除了我的其他答案之外,我还想添加其他使用类型类的解决方案。它更复杂,所以我可以建议你使用简单的隐式转换,我在另一个答案中描述过,如果它解决了你的问题
出于演示目的,我将StrOrSeqStr
重命名为displaybable
,并使其更通用,这样它不仅适用于String
和Seq[String]
,而且适用于任何其他类型,如果类型参数T
也具有displaybable
(它实际上可以与您想要的任何类一起工作-您只需要提供合适的隐式表达式)
首先,您需要定义可显示的:
trait Displayable[T] {
def getString(target: T): String
}
object Displayable {
implicit object StringDisplayable extends Displayable[String] {
def getString(str: String) = str
}
implicit object DateDisplayable extends Displayable[Date] {
val dateFormat = new SimpleDateFormat("dd.MM.yyyy")
def getString(date: Date) = dateFormat format date
}
implicit def seqDisplayable[T: Displayable] = new Displayable[Seq[T]] {
def getString(seq: Seq[T]) = seq map implicitly[Displayable[T]].getString mkString " "
}
}
正如您所看到的,我在companion对象中收集了所有相关的隐式,因此它们总是可用的,并且不需要显式导入(便于将来使用)
这里有趣的方法是seqdisplaybable
——它要求T
也具有displaybable
(这也使得它具有递归性——例如,Seq[Seq[Date]]
也具有可显示性
)。我还为String
和Date
创建了特殊规则。正如您所见,它非常严格,允许String
,Date
,Seq[String],Seq[Date]
,Seq[Seq[String]
,Seq[Seq[String]]
,等等。如果要允许所有其他对象,可以添加如下内容:
implicit def anythingDisplayable[T] = new Displayable[T] {
def getString(anything: T) = anything toString
}
现在是f
功能:
def f[A : Displayable, B : Displayable](a: A, b: B) {
val aIn = implicitly[Displayable[A]].getString(a)
val bIn = implicitly[Displayable[B]].getString(b)
// ...
}
所以我需要证据:对于A
和B
应该存在一些displayible
,然后我使用这些displayible
将它们转换为String
。如果你想进一步简化它,你可以创建从dislplayible
到String
的隐式转换:
implicit def displayableToString[T : Displayable](target: T) =
implicitly[Displayable[T]].getString(target)
def f[A : Displayable, B : Displayable](a: A, b: B) {
val aIn: String = a
val bIn: String = b
//...
}
以下是使用示例:
f(Seq("1"), "2")
f("1", Seq("2", "3"))
f(new Date, Seq("10", "3"))
f(new Date, Seq(Seq("10", "11"), Seq("3", "4")))
f(Seq(new Date, new Date(12345)), "1")
希望这有帮助。据我所知,您试图使用上下文边界,以便为函数f
提供一些可以被视为字符串或可以转换为字符串的内容。除了我的其他答案之外,我还想添加其他使用类型类的解决方案。这更复杂,因此我建议您使用简单的隐式conversion,我在另一个答案中描述过,如果它解决了您的问题
出于演示目的,我将StrOrSeqStr
重命名为displaybable
,并使其更通用,这样它不仅适用于String
和Seq[String]
,而且适用于任何其他类型,如果类型参数T
也具有displaybable
(它实际上可以与您想要的任何类一起工作-您只需要提供合适的隐式表达式)
首先,您需要定义可显示的:
trait Displayable[T] {
def getString(target: T): String
}
object Displayable {
implicit object StringDisplayable extends Displayable[String] {
def getString(str: String) = str
}
implicit object DateDisplayable extends Displayable[Date] {
val dateFormat = new SimpleDateFormat("dd.MM.yyyy")
def getString(date: Date) = dateFormat format date
}
implicit def seqDisplayable[T: Displayable] = new Displayable[Seq[T]] {
def getString(seq: Seq[T]) = seq map implicitly[Displayable[T]].getString mkString " "
}
}
正如您所看到的,我在companion对象中收集了所有相关的隐式,因此它们总是可用的,并且不需要显式导入(便于将来使用)
这里有趣的方法是seqdisplaybable
——它要求T
也具有displaybable
(这也使得它具有递归性——例如,Seq[Seq[Date]]
也具有可显示性
)。我还为String
和Date
创建了特殊规则。正如您所见,它非常严格,允许String
,Date
,Seq[String],Seq[Date]
,Seq[Seq[String]
,Seq[Seq[String]]
,等等。如果要允许所有其他对象,可以添加如下内容:
implicit def anythingDisplayable[T] = new Displayable[T] {
def getString(anything: T) = anything toString
}
现在是f
功能:
def f[A : Displayable, B : Displayable](a: A, b: B) {
val aIn = implicitly[Displayable[A]].getString(a)
val bIn = implicitly[Displayable[B]].getString(b)
// ...
}
所以我需要证据:对于A
和B
应该存在一些displayible
,然后我使用这些displayible
将它们转换为String
。如果你想进一步简化它,你可以创建从dislplayible
到String
的隐式转换:
implicit def displayableToString[T : Displayable](target: T) =
implicitly[Displayable[T]].getString(target)
def f[A : Displayable, B : Displayable](a: A, b: B) {
val aIn: String = a
val bIn: String = b
//...
}
以下是使用示例:
f(Seq("1"), "2")
f("1", Seq("2", "3"))
f(new Date, Seq("10", "3"))
f(new Date, Seq(Seq("10", "11"), Seq("3", "4")))
f(Seq(new Date, new Date(12345)), "1")
希望这有帮助。非常接近,非常接近
trait StrOrSeqStr[A] {
def mkString(x: A): String
}
implicit object Str extends StrOrSeqStr[String] { def mkString(s: String) = s }
implicit object SeqStr extends StrOrSeqStr[Seq[String]] {
def mkString(s: Seq[String]) = s mkString " "
}
def f[A, B](a: A, b: B)(implicit evA: StrOrSeqStr[A], evB: StrOrSeqStr[B]) {
implicit def fromSeqString(s: Seq[String]): String = s mkString ""
val aIn: String = evA mkString a
val bIn: String = evB mkString b
}
// both should work
f(Seq("1"), "2")
f("1", Seq("2", "3"))
接近,非常接近
trait StrOrSeqStr[A] {
def mkString(x: A): String
}
implicit object Str extends StrOrSeqStr[String] { def mkString(s: String) = s }
implicit object SeqStr extends StrOrSeqStr[Seq[String]] {
def mkString(s: Seq[String]) = s mkString " "
}
def f[A, B](a: A, b: B)(implicit evA: StrOrSeqStr[A], evB: StrOrSeqStr[B]) {
implicit def fromSeqString(s: Seq[String]): String = s mkString ""
val aIn: String = evA mkString a
val bIn: String = evB mkString b
}
// both should work
f(Seq("1"), "2")
f("1", Seq("2", "3"))
…或反之亦然-seq2String方法…或反之亦然-seq2String方法。