【问题标题】:Scala tuple unpacking for constructors构造函数的 Scala 元组解包
【发布时间】:2015-09-10 22:06:42
【问题描述】:

我有一个带有两个参数的 Scala 类和另一个参数构造函数。 对于单参数构造函数,我调用一个方法来获取两个元素的元组,并尝试将元组用于需要两个参数的构造函数的参数。这是一个例子:

def vals(v:Int) = {
    // computation
    (v,v) // returns two element tuple
}

class A(a:Int, b:Int) {
    def this(v:Int) = {
        this(vals(v))
    }
}

object Main extends App {
    val a = new A(10)
}

但是,我收到类型不匹配错误。 我在scala tuple unpacking 中找到了一个适用于函数调用但不适用于构造函数的解决方案。

def foo(x: Int, y: Int) = x * y
def getParams = {
    (1,2)  //where a & b are Int
}

object Main extends App {
    println((foo _).tupled(getParams))
    println(Function.tupled(foo _)(getParams))
}

如何解决这个问题?

【问题讨论】:

    标签: scala parameters constructor


    【解决方案1】:

    为该类创建一个伴随对象并向其添加几个“工厂”(“应用”)方法,然后放弃额外的构造函数以支持工厂方法。如果需要,您还可以在其中包含 vals 方法以将事物保持在一起(尽管您也可以在其他地方定义它,如果这对您更有效)。然后你会得到如下的结果:

    class A(val a:Int, val b:Int)
    
    object A {
    
      def apply(pair: (Int, Int)): A = new A(pair._1, pair._2)
    
      def apply(v: Int): A = A(vals(v))
    
      def vals(v:Int) = {
        // computation
        (v,v) // returns two element tuple
      }
    }
    

    并使用以下命令创建您的A

    scala> val a = A(10)
    a: A = A@36d6ec03
    
    scala> a.a
    res6: Int = 10
    

    请注意,我将“a”和“b”字段声明为“val”。这使它们可以访问,如上面的a.a 行所示。事实上,我建议将A 设为“案例类”,例如。 case class(a: Int, b: Int) 自动将 'val' 添加到字段中,并为您创建一个伴随类(另一个默认的“应用”方法采用两个 Ints)。您还可以免费获得toStringequalshashcode 的实现。

    【讨论】:

      【解决方案2】:

      虽然我同意并推荐 Shadowlandsthe answer given,但您可能会在 Scala 2.12.2 之前的版本中遇到编译器错误(请参阅 SI-3772)阻止为方法拥有的定义伴随对象 case 类(根据声明顺序,会导致错误 MyClass is already defined as object MyClassMyClass is already defined as (compiler-generated) case class companion object MyClass)。

      一种非正统的解决方法是向案例类添加两个构造函数:一个接受传递给外部函数的初始值,另一个接受来自计算的元组,该元组被解包为案例类参数的参数。

      def values(i: Int): (Int, String) = i -> i.toString
      
      case class Foo(i: Int, s: String) {
        private def this(values: (Int, String)) = this(values._1, values._2)
        def this(i: Int) = this(values(i))
      }
      
      assert(Foo(10, "10") == new Foo(10))
      

      用引用上述错误的 cmets 显着地装饰它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-14
        • 2011-02-11
        • 2011-03-25
        • 1970-01-01
        • 1970-01-01
        • 2012-09-11
        • 1970-01-01
        • 2013-01-31
        相关资源
        最近更新 更多