【问题标题】:Bounds on constructors?构造函数的界限?
【发布时间】:2023-03-22 15:44:01
【问题描述】:

注意:如果有人能为我想问的问题想出一个更好的标题 - 请提及或编辑。

给定一个包装方法:

trait MyWrapperBound {
  val message: String
}

def wrap[T <: MyWrapperBound](message: String): T

我正在寻找一种方法来描述MyWrapperBound 的所有实现都应该有一个接受message: String 的构造函数,这样我就可以从我的wrap 方法构造并返回它。

我可以想到几种方法来做到这一点:

方法 1 - 使用隐式:

def wrap[T <: MyWrapperBound](message: String)(implicit factory: String => T): T

这意味着任何MyWrapperBound impl。还必须创建隐式:

case class SimpleBound(message: String) extends MyWrapperBound

object SimpleBound {
  implicit def factory(message: String): SimpleBound = SimpleBound(message)
}

这会产生相当多的样板文件——我想避免这种情况。

方法 2 - 宏:

def wrap[T <: MyWrapperBound](message: String): T = macro ...

宏将采用类型,断言存在有效的构造函数,如果存在则构造类型,如果不存在则抛出一个很好的编译错误供开发人员去修复(通过添加有效的构造函数)

我的问题是 - 对 scala 来说相当新,是否有一个更简单的选项我错过了?还是其他更有意义的选择?

【问题讨论】:

  • 方法一和方法二是不同的东西。在方法 1 中,您将讨论如何使用隐式实现它,在方法 2 中,您将讨论如何使用宏进行验证。您的意思是说您要使用方法 2 中的宏为该类型生成构造函数?
  • 是的,它们是实现同一目标的不同方式。方法 2 只会在构造函数已经存在的情况下验证和使用构造函数。如果它不存在,则由开发人员自行添加以修复编译时错误。
  • @YuvalItzchakov - 我刚刚看到我犯的错误,我相信这导致了你的评论。宏版本并不意味着有一个隐式参数....抱歉有任何混淆。

标签: scala macros implicit


【解决方案1】:

如果您愿意接受类型类,则有一个涉及隐式的稍微简单的答案。您可以通过向MyWrapperBound 添加类型参数并使用Show 类型类枚举您希望支持的消息类型来轻松完成您想做的事情。例如,如果您知道您尝试包装的所有内容都支持映射 A =&gt; String,您可以为您的 wrap 方法提供 Show[A] 隐式,如下所示:

trait Show[A] {

  def show(a: A): String
}

trait MyWrapperBound[A] {

  val message: String

}

object MyWrapperBound {

  def wrap[A](a: => A)(implicit ev: Show[A]): MyWrapperBound[A] =
    new MyWrapperBound[A] {
      override val message: String = ev.show(a)
    }
}

object ShowInstances {

  case class MyDS(someInformation: List[String])

  implicit val simpleShow: Show[String] = new Show[String] {
    override def show(a: String): String = a
  }

  implicit val slightlyMoreComplexShow: Show[MyDS] = new Show[MyDS] {
    override def show(a: MyDS): String = a.someInformation.mkString("[", ",", "]")
  }
}

与往常一样,代码编译并产生所需的输出。添加更多支持就像向ShowInstances 添加更多实例一样简单。这允许您将映射A =&gt; String 与包装逻辑本身解耦,以便wrap 成为MyWrapperBound 的简单构造函数。

如果您不喜欢使用类型参数对 MyWrapperBound 进行参数化的想法,那么即使您不打算将其实例编入某些消息类型的索引,也没有必要。

【讨论】:

    猜你喜欢
    • 2013-03-04
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 2013-08-26
    相关资源
    最近更新 更多