有没有一种简单的方法将一个case class转换为元组?
当然,我可以轻松地编写样板代码来完成此操作,但我的意思是不使用样板代码。
实际上,我想要的是一种方便地使一个case class按字典顺序排序的方法。我可以通过导入scala.math.Ordering.Implicits._来为元组实现排序,然后我的元组就有了一个定义。但是scala.math.Ordering中的隐式参数通常不适用于所有的case classes。
有没有一种简单的方法将一个case class转换为元组?
当然,我可以轻松地编写样板代码来完成此操作,但我的意思是不使用样板代码。
实际上,我想要的是一种方便地使一个case class按字典顺序排序的方法。我可以通过导入scala.math.Ordering.Implicits._来为元组实现排序,然后我的元组就有了一个定义。但是scala.math.Ordering中的隐式参数通常不适用于所有的case classes。
尝试在伴生对象中调用unapply().get
,怎么样?
case class Foo(foo: String, bar: Int)
val (str, in) = Foo.unapply(Foo("test", 123)).get
// str: String = test
// in: Int = 123
Shapeless会为您完成这个操作。
import shapeless._
import shapeless.syntax.std.product._
case class Fnord(a: Int, b: String)
List(Fnord(1, "z - last"), Fnord(1, "a - first")).sortBy(_.productElements.tupled)
res0: List[Fnord] = List(Fnord(1,a - first), Fnord(1,z - last))
productElements可以将一个case class转换为Shapeless HList:
scala> Fnord(1, "z - last").productElements
res1: Int :: String :: shapeless.HNil = 1 :: z - last :: HNil
而HLists则通过#tupled转换为元组:
scala> Fnord(1, "z - last").productElements.tupled
res2: (Int, String) = (1,z - last)
性能可能会很差,因为你不断进行转换。你可能会将所有内容转换为元组形式,对其进行排序,然后使用类似于(Fnord.apply _).tupled
的方法将其转换回来。
Scala 3首次全面支持在case类和元组之间进行转换:
scala> case class Foo(foo: String, bar: Int)
// defined case class Foo
scala> Tuple.fromProductTyped(Foo("a string", 1))
val res0: (String, Int) = (a string,1)
scala> summon[deriving.Mirror.ProductOf[Foo]].fromProduct(res0)
val res1: deriving.Mirror.ProductOf[Foo]#MirroredMonoType = Foo(a string,1)
我在尝试做同样的事情时,发现了这个旧帖子。最终我选择了这个解决方案:
case class Foo(foo: String, bar: Int)
val testFoo = Foo("a string", 1)
val (str, in) = testFoo match { case Foo(f, b) => (f, b) }
unapply
返回的Option
上调用.get
。我想知道为什么一个case类没有一个名为.toTuple
的方法,它返回字面元组,而不是一个Option
;也就是说,你正在做的事情。对于case类实例的.unapply
,结果将始终是'Some',迫使我调用.get
,这是一种代码味道。 - chaotic3quilibrium你可以尝试扩展ProductN
特质,其中N=1-22,它继承了TupleN
。这将为您提供许多元组语义,例如_1
、_2
等方法。根据您使用类型的方式,这可能足以满足您的需求,而无需创建实际的元组。
val thisTuple: Ordered[(String, Int)] = Foo.unapply(this).get; val thatTuple = Foo.unapply(that).get; thisTuple compare thatTuple
。虽然这不是世界上最漂亮的东西,但我仍然愿意听取建议,但你的答案肯定能完成任务。谢谢! - Douglasget()
,只能使用get
。 - Slow Harryunapply
返回的Option
上调用.get
是一种代码异味,即不良实践。因此,这个答案相当粗略。有关更好的答案,请参见此答案,在其中安全而彻底地处理了.get
:https://dev59.com/-Wsz5IYBdhLWcg3wJUfJ#43310062 - chaotic3quilibrium.unapply
的方法契约保证Option
将是Some
- 在其他情况下它将是None
。在其他情况下,我们可能不知道,但在这里我们知道,并且不必在运行时验证此契约。因此,调用.get
是可以的。 - ig-dev