【问题标题】:Type-safe Builder: How to set compiler error message类型安全生成器:如何设置编译器错误消息
【发布时间】:2013-01-12 20:17:44
【问题描述】:

我在类型安全的构建器模式中使用幻像类型来确保方法只被调用一次,如下面的代码示例所示

  sealed trait TBoolean
  sealed trait TTrue extends TBoolean
  sealed trait TFalse extends TBoolean

  class Builder[MethodCalled <: TBoolean] private() {

    def foo()(implicit ev: MethodCalled =:= TFalse): Builder[TTrue] = {
      new Builder[TTrue]
    }
  }

  object Builder {
    def apply() = new Builder[TFalse]()
  }

Builder().foo().foo() 不能按要求工作,但是我想将错误消息设置为用户可读的内容。目前消息是

此行有多个标记 - 方法 foo 的参数不足:(隐式 ev: =:=[W.TTrue,W.TFalse])W.Builder[W.TTrue]。未指定值参数 ev。 - 无法证明 W.TTrue =:= W.TFalse。 - 无法证明 W.TTrue =:= W.TFalse。

【问题讨论】:

    标签: scala


    【解决方案1】:

    在这里使用类型参数有点矫枉过正。最好只从 foo 方法返回一个能力较差的类型:

    object Builder {
      trait CanFoo { def foo() : Builder }
      def apply(): Builder with CanFoo = new Builder with CanFoo {
        def foo() = new Builder {}
      }
    }
    trait Builder
    
    Builder().foo().foo() // value foo is not a member of Builder
    

    有一个注解implicitNotFound,其中can be used用于自定义错误信息,但需要定义为寻找的类型(=:=)而不是使用站点(foo),@987654322 @...

    ...除非您为=:= 创建自己的替代品:

    import annotation.implicitNotFound
    
    object Called {
      implicit def same[A]: Called[A, A] = instance.asInstanceOf[Called[A, A]]
      private object instance extends Called[Any,Any]
    }
    @implicitNotFound(msg = "Cannot call this method twice") sealed trait Called[A, B]
    
    class Builder[Foo <: TBoolean] private() {
      def foo()(implicit ev: Called[Foo, TFalse]): Builder[TTrue] = {
        new Builder[TTrue]
      }
    }
    object Builder {
      def apply() = new Builder[TFalse]()
    }
    
    Builder().foo().foo()  // -> "error: Cannot call this method twice"
    

    【讨论】:

    • 将特征称为NotCalled 而不是Called 可能是谨慎的。否则,很棒的帖子 +1。
    • 表示方法已被调用,因此不符合再次调用的条件。这个名字对我来说似乎很合适。
    • 或使用类型别名type NotCalled[A] = Called[A, TFalse]
    • 感谢您的回答!请参阅我为什么要使用类型参数的另一篇文章:stackoverflow.com/questions/14283938/…
    【解决方案2】:

    您无法自定义错误消息,但您可以自定义您的特征名称。我会称他们为BuiltUnbuilt 或类似的名称。然后你可以警告图书馆的用户或任何你会收到看起来毛茸茸的错误消息的东西,但他们真的只需要发现看起来像 Cannot prove that Built =:= Unbuilt 的东西。

    【讨论】:

      猜你喜欢
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      相关资源
      最近更新 更多