Przeciążenie konstruktora Scala?

135

Jak zapewnić przeciążone konstruktory w Scali?

Landon Kuhn
źródło

Odpowiedzi:

186

Warto wyraźnie wspomnieć, że konstruktory pomocnicze w Scali muszą albo wywołać odpowiedź głównego konstruktora (jak w landon9720), albo innego pomocniczego konstruktora z tej samej klasy, jako swoją pierwszą akcję. Nie mogą po prostu wywołać konstruktora nadklasy jawnie lub niejawnie, tak jak w Javie. Zapewnia to, że główny konstruktor jest jedynym punktem wejścia do klasy.

class Foo(x: Int, y: Int, z: String) {  
  // default y parameter to 0  
  def this(x: Int, z: String) = this(x, 0, z)   
  // default x & y parameters to 0
  // calls previous auxiliary constructor which calls the primary constructor  
  def this(z: String) = this(0, z);   
}
Jon McAuliffe
źródło
@Jon McAuliffe: Zły przykład? Bez drugiego i trzeciego konstruktora użytkownik nadal może dzwonić new Foo(x=2,z=4)i new Foo(z=5)jeśli zmienisz pierwszą linię naclass Foo(x: Int = 0, y: Int = 0, z: String) {
user2987828
Nazwane / domyślne argumenty pojawiły się dopiero w Scali 2.8.
Jon McAuliffe,
2
Warto byłoby wspomnieć, jak używać konstruktora przeciążenia. Nie jest trywialne, że newsłowo kluczowe jest konieczne nawet w przypadku klas przypadków.
Readren
33
 class Foo(x: Int, y: Int) {
     def this(x: Int) = this(x, 0) // default y parameter to 0
 }
Landon Kuhn
źródło
16

Począwszy od Scala 2.8.0 możesz również mieć domyślne wartości parametrów contructor- i method. Lubię to

scala> class Foo(x:Int, y:Int = 0, z:Int=0) {                           
     | override def toString() = { "Foo(" + x + ", " + y + ", " + z + ")" }
     | }
defined class Foo

scala> new Foo(1, 2, 3)                                                    
res0: Foo = Foo(1, 2, 3)

scala> new Foo(4)                                                          
res1: Foo = Foo(4, 0, 0)

Parametry z wartościami domyślnymi muszą występować po parametrach bez wartości domyślnych na liście parametrów.

Jörgen Lundberg
źródło
3
Nie działa to jednak w przypadku nietrywialnych ustawień domyślnych. więc class Foo(val x:Int, y:Int=2*x)nie działa.
podsub
@ Jörgen Lundberg: napisałeś Parametry z wartościami domyślnymi muszą występować po tych, które nie mają wartości domyślnych na liście parametrów. To źle, new Foo(x=2,z=4)wydrukuje Foo(2,0,4).
user2987828
@ user2987828 miałem na myśli to, że nie możesz napisać nowego Foo (12, x = 2), musisz napisać nowe Foo (x = 2, 12). Możesz napisać nowe Foo (12, y = 2), a otrzymasz Foo (12, 2, 0)
Jörgen Lundberg
10

Patrząc na mój kod, nagle zdałem sobie sprawę, że trochę przeładowałem konstruktora. Potem przypomniałem sobie to pytanie i wróciłem, aby udzielić innej odpowiedzi:

W Scali nie możesz przeciążać konstruktorów, ale możesz to zrobić za pomocą funkcji.

Wiele osób decyduje się również na uczynienie applyfunkcji obiektu towarzyszącego fabryką dla odpowiedniej klasy.

Uczyniając tę ​​klasę abstrakcyjną i przeciążając applyfunkcję w celu zaimplementowania tej klasy, otrzymujesz przeciążony „konstruktor”:

abstract class Expectation[T] extends BooleanStatement {
    val expected: Seq[T]}

object Expectation {
    def apply[T](expd:     T ): Expectation[T] = new Expectation[T] {val expected = List(expd)}
    def apply[T](expd: Seq[T]): Expectation[T] = new Expectation[T] {val expected =      expd }

    def main(args: Array[String]): Unit = {
        val expectTrueness = Expectation(true)}
}

Zauważ, że jawnie definiuję każdy applyz nich do zwrotu Expectation[T], w przeciwnym razie zwróciłoby to kaczkę wpisaną Expectation[T]{val expected: List[T]}.

latające owce
źródło
0

Spróbuj tego

class A(x: Int, y: Int) {
  def this(x: Int) = this(x, x)
  def this() = this(1)
  override def toString() = "x=" + x + " y=" + y
  class B(a: Int, b: Int, c: String) {
    def this(str: String) = this(x, y, str)
    override def toString() =
      "x=" + x + " y=" + y + " a=" + a + " b=" + b + " c=" + c
  }
}
anish
źródło