【问题标题】:'with' keyword usage in scala with case classes带有案例类的scala中的'with'关键字用法
【发布时间】:2020-11-30 03:21:42
【问题描述】:

如果这样的事情在 scala 中有意义的话:

object CaseClassUnion extends App {
  case class HttpConfig(bindUrl: String, port: String)
  case class DbConfig(url: String, usr: String, pass: String)

  val combined: HttpConfig with DbConfig = ???
  
  //HttpConfig("0.0.0.0", "21") ++ DbConfig("localhost", "root", "root") 
  //would be nice to have something like that
}

至少这样编译...有没有办法,可能使用宏魔法来实现给定实例的两个类的联合? 在 zio 中,我相信有类似的东西:

val live: ZLayer[ProfileConfiguration with Logging, Nothing, ApplicationConfiguration] =
ZLayer.fromServices[ProfileConfigurationModule.Service, Logger[String], Service] { (profileConfig, logger) =>  ???

我们将ProfileConfiguration with Logging 转换为ProfileConfigurationModule.Service, Logger[String] => Service 的函数

【问题讨论】:

  • 你不能扩展案例类,它们should be final - 你想要做的是定义所有接口的两个特征,然后创建一个扩展这两个特征的单个案例类。 - 你不能神奇地混合两个值来得到一个交集类型,你也可以只使用一个元组。
  • Vanilla Scala 不支持两个案例类的产品。您可以将HList 用于这两种类型,然后产品类型将类似于val combined: HttpConfig :: DbConfig :: HNil = httpConfig :: dbConfig:: HNil。如果你想使用 vanilla Scala,你必须自己做样板并定义一个新的案例类。
  • @texasbruce, (HttpConfig, DbConfig) 是两个案例类的产物...(使用元组是不是一个好主意完全是另一回事)
  • @LeviRamsey 我的意思是将两个案例类的产品组合成一个案例类

标签: scala types case-class


【解决方案1】:

几件事。

当您有多个 traits 和 with 组合时,Scala 会进行特征线性化以将它们组合成一个具有线性层次结构的类。但是对于没有构造函数的traits 来说确实如此!

case class(这不是一个特征)不能用另一个case class(根本)扩展,因为这会破坏合同,例如:

case class A(a: Int)
case class B(a: Int, b: String) extends A(a)

A(1) == B(1, "") // because B is A and their respective fields match
B(1, "") != A(1) // because A is not B
B(1, "").hashCode != A(1).hashCode // A == B is true but hashCodes are different!

这意味着您甚至无法手动生成case class 组合。你想“组合”它们,使用一些产品:一个元组,另一个案例类等。

如果你对 ZIO 感兴趣的话:

  • 使用特征
  • 使用它们作为某种类型级别的技巧来表示一组无序的依赖项,其中类型推断将在您组合操作时计算集合总和,并使用一些巧妙的技巧从列表中删除特征,使用 .provide 删除依赖项集合
  • ZLayers 只是让这些恶作剧变得更容易

所以,如果你甚至传递了一些A with B,你要么使用蛋糕模式自己组合它,要么你一个一个地传递依赖项。 ZIO 开发人员可能永远不会遇到需要一些宏来组合多个案例类 (.provide(combineMagically(A, B, C, D, ...)) 的问题,因为他们可以一个一个地传递每个依赖项的实现 (.provide(A).provide(B)),并且下面的代码永远不需要这些的组合类型作为一个值 - 这只是一个编译时技巧,可能永远不会转化为 A with B with C with D ... 类型的实际值的要求。

TL;DR:您不能生成 2 个案例类的组合; ZIO 使用复合类型作为某种类型级别的集合来跟踪依赖关系,它实际上并不需要创建复合类型的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    • 2018-12-10
    • 1970-01-01
    相关资源
    最近更新 更多