【问题标题】:define default named arguments in terms of other arguments in scala根据scala中的其他参数定义默认命名参数
【发布时间】:2013-08-14 09:02:44
【问题描述】:

我有一个存储三个绑定参数的案例类。我想定义可以从任意两个参数构建类的伴生对象,类似于下面的示例,这显然是不正确的:

def test(start : Float = end - duration, duration : Float = end - start, end : Float = start + duration) {
  require( abs(start + duration - end) < epsilon )
  ...
}
val t1 = test(start = 0f, duration = 5f)
val t2 = test(end = 4f, duration = 3f)
val t3 = test(start = 3f, end = 5f)

我可以使用什么技巧来获得类似的用法语法?

【问题讨论】:

    标签: scala named-parameters


    【解决方案1】:

    您可以使用类型类:

    // Represents no argument
    object NoArg
    
    // Resolves start, duration, stop
    trait DurationRes[A,B,C] {
      def resolve(s: A, d: B, e: C): (Float, Float, Float)
    }
    
    object DurationRes {
      implicit object startEndRes extends DurationRes[Float, NoArg.type, Float] {
        def resolve(s: Float, d: NoArg.type, e: Float) = (s, e-s, e)
      }
      implicit object startDurRes extends DurationRes[Float, Float, NoArg.type] {
        def resolve(s: Float, d: Float, e: NoArg.type) = (s, d, s+d)
      }
      // etc.
    }
    
    def test[A,B,C](start: A = NoArg, dur: B = NoArg, end: C = NoArg)
                   (implicit res: DurationRes[A,B,C]) {
      val (s,d,e) = res.resolve(start, dur, end)
      // s is start, d duration, e end
    }
    
    test(start = 1f, end = 2f)
    

    这样它甚至是类型安全的,你不能调用类似的东西:

    test(start = 1f)
    

    甚至

    test()
    

    【讨论】:

      【解决方案2】:

      经过一番思考,我提出了另一种解决方案(我并不是说它更好,只是想知道它是否可以接受)。本质是定义一个类: class Klass(val x: Int, val y: Int, val z: Int) 和一个伴随对象:

      object Klass {
        def apply(x: Int, y: Int)(z: Int = x + y) = {
          new Klass(x, y, z)
        }
        // and so on
      }
      

      因此您可以执行val k = Klass(x = 5, y = 6)() 并让val k 引用Klass(5, 6, 11) 实例。

      而且由于代码量少,可能可以定义一个宏来完成这项工作,但这对我来说有点困难,但这是一个有趣的练习。

      更新

      一段时间后,我想提醒您,您的情况只有三个参数组合,那么手动提供 3 个apply() 方法不是更容易吗? apply(s, d), apply(s, e), apply(d, e) 应该可以满足您的需求。这样可以节省一些打字时间,因为使用其他方法基本上也必须编写所有这些情况。

      【讨论】:

      • 请注意,这仅在您的参数具有不同类型时才有效。由于 Java 兼容性,您不能像这样重载 apply。 (在 Java 中,参数名称不是公共接口的一部分)。
      猜你喜欢
      • 2012-03-14
      • 1970-01-01
      • 2015-04-21
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多