Scala可互换的通用类型

时间:2015-10-16 03:26:57

标签: scala generics types

我对Scala编程非常陌生,我非常喜欢代码可组合的程度。我想编写一些处理两个可相互转换的相关对象的特性,并通过继续扩展该特征来构建更多功能,这样当我创建对象时,我可以为我的泛型指定相关类型。这是我正在谈论的代码类型的工作玩具示例:

trait FirstConverter[First] {
  def toFirst: First
}

trait SecondConverter[Second] {
  def toSecond: Second
}

trait TwoWayConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] {
  def firstToSecond(x: First) = x.toSecond
  def secondToFirst(x: Second) = x.toFirst
}

trait RoundTripConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] extends TwoWayConverter[First, Second] {
  def firstToFirst(x: First) = secondToFirst(firstToSecond(x))
  def secondToSecond(x: Second) = firstToSecond(secondToFirst(x))
}

case class A(s: String) extends SecondConverter[B] {
  def toSecond: B = B((s.toInt) + 1)
}

case class B(i: Int) extends FirstConverter[A] {
  def toFirst: A = A((i * 2).toString)
}

object ABConverter extends RoundTripConverter[A, B]

object Main {
  def main(args: Array[String]): Unit = {
    println(ABConverter firstToSecond A("10")) // 11
    println(ABConverter secondToFirst B(42)) // 84
    println(ABConverter firstToFirst A("1")) // 4
    println(ABConverter secondToSecond B(2)) // 5
  }
}

虽然这有效,但我不确定它是否是惯用的Scala。我问是否有任何技巧可以使类型定义更简洁,如果我能以某种方式定义类型限制只有一次,并让它们被多个特征使用,扩展其他特征。

提前致谢!

1 个答案:

答案 0 :(得分:3)

改进设计的一种方法是使用类型类,而不是继承自SecondConverterA。这样,您可以为相同类型使用多个转换函数,并在您无法控制的类之间进行转换。

一种方法是创建一个可以将B转换为trait Converter[A, B] { def convert(a: A): B } trait TwoWayConverter[A, B] { def firstToSecond(a: A)(implicit conv: Converter[A, B]): B = conv.convert(a) def secondToFirst(b: B)(implicit conv: Converter[B, A]): A = conv.convert(b) } trait RoundTripConverter[A, B] extends TwoWayConverter[A, B] { def firstToFirst(a: A)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) = secondToFirst(firstToSecond(a)) def secondToSecond(b: B)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) = firstToSecond(secondToFirst(b)) } 的类型类:

Foo

我们可以为以下两个类BarA创建类似于Bcase class Foo(s: String) case class Bar(i: Int) implicit val convFooBarFoor = new Converter[Foo, Bar] { def convert(foo: Foo) = Bar((foo.s toInt) + 1) } implicit val convBarFoo = new Converter[Bar, Foo] { def convert(bar: Bar) = Foo((bar.i * 2) toString) }

的类型类实例
FooBarConverter

然后我们可以创建一个object FooBarConverter extends RoundTripConverter[Foo, Bar] FooBarConverter firstToSecond Foo("10") // Bar(11) FooBarConverter secondToFirst Bar(42) // Foo(84) FooBarConverter firstToFirst Foo("1") // Foo(4) FooBarConverter secondToSecond Bar(2) // Bar(5)

Converter

唯一的问题是因为我们无法将参数传递给特征,我们不能将类型限制为具有StringIntConverter类型类实例的类型。因此,即使没有Converter[String, Int]和/或Convert[Int, String]个实例,您也可以在下面创建object StringIntConverter extends TwoWayConverter[String, Int]

StringIntConverter.firstToSecond("a")

您无法调用firstToSecond,因为{{1}}方法需要两个提到的类型类实例的隐式证据。