Первичный конструктор Kotlin вызывает вторичный конструктор

Почему это не компилируется?

class test
{
  constructor() {
      var a = Date().day
      this(a)
  }

  constructor(a:Int) {
  }
}

ошибка: выражение 'this' типа 'test' не может быть вызвано как функция. Функция invoke() не найдена.

Предлагаемое исправление состоит в том, чтобы добавить это:

private operator fun invoke(i: Int) {}

Зачем?

3 ответа

Во-первых, оба этих конструктора являются вторичными конструкторами. Первичный конструктор - это тот, который находится вне тела класса.

Во-вторых, как описано в документации, правильный синтаксис для вызова другого конструктора выглядит следующим образом:

class Test {
    constructor() : this(1) { }

    constructor(a: Int) { }
}
class test constructor(){ // primary constructor (The primary constructor is part of the class header: it goes after the class name (and optional type parameters))

    constructor(a: Int) : this() { // secondary constructor

    }
}

Если ваш класс должен определить primary constructor, secondary constructor необходимо делегировать primary constructor, Смотрите здесь.

Я думаю primary constructor нельзя звонить из secondary constructor,

Вы можете думать так: вторичные звонки первичные и первичные звонки вторичные => бесконечный цикл => невозможно

В вашем случае есть 2 secondary constructorтак что вы можете сделать как

class test {

    constructor() : this(Date().day) // I see it quite like Java here https://stackru.com/questions/1168345/why-do-this-and-super-have-to-be-the-first-statement-in-a-constructor

    constructor(a: Int) {
    }
}

Пара вещей здесь не так:

  • Классы должны всегда использовать верблюжий кейс для своих имен (test -> Test)
  • Вы не можете вызвать другой конструктор, как вы пытались this(1) внутри тела других конструкторов)

Я думаю, что вы на самом деле хотите a являясь свойством и, альтернативно, инициализировать его значением по умолчанию. Вы могли бы сделать это так

class Test(val a: Int) {
    constructor() : this(1) // notice how you can omit an empty body
}

или даже лучше, вот так:

class Test(val a: Int = 1) // again an empty body can be omitted.

Редактировать:

Если вам нужно сделать некоторые расчеты, как указано в комментарии ниже, ответ Йоль:

class Test(val day: Int) {
    // you can use any expression for initialization
    constructor(millis: Long) : this(Date(millis).day) 
}

или если все усложняется:

class Test(var day: Int) {
    // pass something (i.e. 1) to the primary constructor and set it properly in the body
    constructor(millis: Long) : this(1) { 
        // some code
        day = // initialize day
    }
}
Другие вопросы по тегам