假设我有一个接受大量参数的方法,每个参数可以是String或Seq [String]。在方法内部,我希望每个参数的值只是值,如果它是一个字符串,并且如果它是Seq [String]则在Seq上的mkString“”。我意识到左/右可能在这里使用,但我不希望调用者必须包装任何args。
我使用implicits强制arg为String或Seq [String]但是我无法弄清楚如何让arg将自身减少为字符串,无论是作为标识还是作为mkString,视情况而定。理想的代码可能如下所示:
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"))
有什么建议吗?谢谢!
答案 0 :(得分: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"))
答案 1 :(得分:3)
implicit def stringsToString(s: Seq[String]) = s mkString " "
def f(s: String *) {
println(s mkString " ")
}
scala> f("1")
1
scala> f("1", "2")
1 2
scala> f(Seq("1", "2"))
1 2
scala> f(Seq("1"), Seq("2"))
1 2
scala> f("1", Seq("2"))
1 2
scala> f(Seq("1"), "2")
1 2
答案 2 :(得分:1)
据我所知,你试图使用上下文边界来赋予函数f
一些可被视为String
或可以转换为它的东西。除了我的其他答案,我想添加其他使用类型类的解决方案。它更复杂,所以我建议你使用简单的隐式转换,我在另一个答案中描述,如果它解决了你的问题。
出于演示目的,我将StrOrSeqStr
重命名为Displayable
并使其更通用,因此它不仅适用于String
和Seq[String]
,还适用于任何其他类型和Seq[T]
如果类型参数T
也有Displayable
(它实际上可以用于您想要的任何类 - 您只需提供合适的隐式)。
首先,您需要定义Displayable
:
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 " "
}
}
正如您所看到的,我收集了伴随对象中的所有相关含义,因此它们始终可用且不需要显式导入(适合将来使用)。
此处有趣的方法是seqDisplayable
- 它还需要T
Displayable
(这也会使其递归 - 例如Seq[Seq[Date]]
也会Displayable
}})。我还为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)
// ...
}
所以我需要证据:Displayable
和A
应该存在一些B
,然后我使用这些String
将它们转换为Displayable
。如果您想进一步简化它,可以从Dislplayable
到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")
希望这有帮助。
答案 3 :(得分:0)
关闭,非常接近...
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"))