构造函数的 Scala 元组解包
Scala tuple unpacking for constructors
我有一个 Scala class 有两个参数,另一个是一个参数构造函数。
对于单参数构造函数,我调用了一个方法来获取两个元素的元组,并尝试将该元组用作需要两个参数的构造函数的参数。这是一个例子:
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))
}
如何解决这个问题?
为 class 创建一个伴随对象并向其添加几个 "factory" ("apply") 方法,然后放弃额外的构造函数以支持工厂方法。如果需要,您还可以在此处包含 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",例如。 case class(a: Int, b: Int)
会自动将 'val' 添加到字段中,并且还会为您创建一个伴随 class(另一种默认的 "apply" 方法需要两个 Int
s) .您还可以免费获得 toString
、equals
和 hashcode
的实现。
虽然我同意并推荐 by Shadowlands, you might encounter a compiler bug in versions prior to Scala 2.12.2 (see SI-3772) 阻止为方法拥有的 case classes 定义伴随对象(这取决于声明顺序,导致错误 MyClass is already defined as object MyClass
或 MyClass is already defined as (compiler-generated) case class companion object MyClass
).
一个非正统的解决方法是向您的案例添加两个构造函数class:一个接受传递给外部函数的初始值,另一个接受来自您的计算的元组,该元组被解包为案例的参数class' 参数.
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))
用引用上述错误的评论显眼地装饰它。
我有一个 Scala class 有两个参数,另一个是一个参数构造函数。 对于单参数构造函数,我调用了一个方法来获取两个元素的元组,并尝试将该元组用作需要两个参数的构造函数的参数。这是一个例子:
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))
}
如何解决这个问题?
为 class 创建一个伴随对象并向其添加几个 "factory" ("apply") 方法,然后放弃额外的构造函数以支持工厂方法。如果需要,您还可以在此处包含 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",例如。 case class(a: Int, b: Int)
会自动将 'val' 添加到字段中,并且还会为您创建一个伴随 class(另一种默认的 "apply" 方法需要两个 Int
s) .您还可以免费获得 toString
、equals
和 hashcode
的实现。
虽然我同意并推荐 MyClass is already defined as object MyClass
或 MyClass is already defined as (compiler-generated) case class companion object MyClass
).
一个非正统的解决方法是向您的案例添加两个构造函数class:一个接受传递给外部函数的初始值,另一个接受来自您的计算的元组,该元组被解包为案例的参数class' 参数.
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))
用引用上述错误的评论显眼地装饰它。