члены класса scala, вызывающие ошибку «Класс« класс »должен быть объявлен как абстрактный или реализовать элемент« член »» - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь выучить Scala Объект s и Класс .Я пришел из Java , которая очень похожа на Scala, но не в синтаксисе.

В Java я бы создал такой класс:

public class Wallet {
    private PublicKey publicKey;
    private PrivateKey privateKey;
    private int balance = 0;

    public Wallet() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        privateKey = keyPair.getPrivate();
        publicKey = keyPair.getPublic();
    }

    public int getBalance(){
        return balance;
    }
}

Это определяет шаблон Wallet объекта, который я могу создать в Java как:

Wallet wallet = new Wallet();

Это также создаст PrivateKey и PublicKey вконструктор Wallet и назначить его соответствующим членам класса.

Я понимаю, что Scala использует слегка отличающийся подход, где классы - это просто шаблоны экземпляров объектов, а Object - это объекты типа Singleton, которые постоянно хранят информацию.

Кроме того, я обнаружил, что Object часто используется в файле Class в качестве объекта-компаньона в соответствии с этого поста .

Используя приведенный выше пример Wallet, я пытаюсь воссоздать его в Scala .Это то, что у меня пока есть:

class Wallet {

  var publicKey: PublicKey
  var privateKey: PrivateKey
  var balance: Int = 0

  def this() {
    this
    val keyPair =  KeyPairGenerator.getInstance("SHA-256").generateKeyPair()
    privateKey = keyPair.getPrivate
    publicKey = keyPair.getPublic
  }

  def getBalance(): Int = {
    balance
  }
}

Проблема:

Класс 'Кошелек' должен быть либо объявлен абстрактным, либо реализовать абстрактный член 'publicKey: PublicKey 'in' com.simple.blockchain.Wallet

Теперь это меня смущает.

В Java , этообычно было бы проблемой объявить, но не реализованные объекты в качестве членов класса, поэтому, если я попытаюсь добавить Companion Object , как предлагалось в предыдущем сообщении SO, и следуя их предложению с помощью:

object Wallet {
  var privateKey: PrivateKey
  var publicKey: PublicKey
}

Я получаю сообщение об ошибке:

Только классы могут быть объявлены, но неопределенные члены

TL; DR

Я быхотел бы иметь Wallet Java код для Scala код, как мне этого добиться?


ОБНОВЛЕНИЕ (чтобы уточнить мой оригинальный вопрос)

Итак, ответ не отражает мой актуальный вопрос (что я имел в виду).Я попытаюсь уточнить.

Существуют различные конструкторы, поддерживаемые Scala.

Первичные конструкторы, которые вы найдете, как упомянуто @Josh здесь

class Person(name: String) {
    var personName: String = name
}

и вторичные конструкторы будут (путем расширения примера @ Джоша), такие как:

def this() {
    this("Unknown Person Name")
    // additional code
}

Эти конструкторы обсуждаются здесь, в некоторых деталях , это делает для хорошего чтения.

Что меня интересует, так это.

Поскольку я объявил члена privateKey и publicKey, поэтому я хочу объявить больше членов в моем классе.Не все эти члены будут созданы при инициализации класса, но будут позже во время выполнения приложения.

Это ниже даст больше контекста тому, что я описал выше.Я создам экземпляр Wallet, а на более поздней стадии позвоню wallet.generateKeys().

class Wallet {

  var publicKey: PublicKey
  var privateKey: PrivateKey
  var balance: Int = 0

  def generateKeys(): Unit = {
    val keyPair =  KeyPairGenerator.getInstance("SHA-256").generateKeyPair()
    privateKey = keyPair.getPrivate
    publicKey = keyPair.getPublic
  }

  def getBalance(): Int = {
    balance
  }
}

Для этого потребуется объявленная, но необработанная переменная во время выполнения, вплоть до точки, где она необходима.

Как этот будет определен в коде Scala.

Ответы [ 4 ]

0 голосов
/ 25 февраля 2019

Если вам нужно иметь значения, которые не инициализируются при создании объекта, лучше всего сделать их Option значения:

class Wallet {
  private var publicKey: Option[PublicKey] = None
  private var privateKey: Option[PrivateKey] = None
  private var balance: Int = 0

  def generateKeys(): Unit = {
    val keyPair =  KeyPairGenerator.getInstance("SHA-256").generateKeyPair()
    privateKey = Some(keyPair.getPrivate)
    publicKey = Some(keyPair.getPublic)
  }

  def getBalance = balance
}

Это безопаснее, чем использовать null, потому что типsystem и runtime проверит, что значение является действительным, когда вы его используете.

Но другие ответы верны, что лучше отложить создание этого объекта, пока ключи не станут доступны, если это возможно.

0 голосов
/ 25 февраля 2019

Вы можете добавить заявку на объект-компаньон:

class Wallet private (val privateKey: PrivateKey, publicKey: PublicKey, balance: Int) {
  def getBalance(): Int = balance
}
object Wallet {
  def apply(): Wallet = {
    val keyPair =  KeyPairGenerator.getInstance("SHA-256").generateKeyPair()
    val privateKey = keyPair.getPrivate
    val privateKey = keyPair.getPublic
    new Wallet(privateKey, privateKey, 0)
  }
}
0 голосов
/ 25 февраля 2019

Это можно сделать, но это запах кода .Предположим, кто-то делает экземпляр вашего кошелька.Они должны позвонить generateKeys, прежде чем ваш класс станет действительно полезным.Если они забудут и попытаются использовать ключи, они получат ошибку во время выполнения или бессмысленное поведение.Вместо этого установите их в главном конструкторе (как Джош предлагает ) или в методе фабрики / применения (как Энди предлагает ).

Но мне нравятся анти-паттерны икод пахнет!

Если вы действительно хотите иметь объявленное, но неинициализированное поле ... вы не можете, даже в Java.В Java неинициализированные поля неявно инициализируются значением по умолчанию (null для объектов).Вы можете получить это поведение в Scala, назначив ему подчеркивание (_):

var publicKey: PublicKey = _
var privateKey: PrivateKey = _

Они будут инициализированы нулем.Пожалуйста, не делайте этого.

Другие проблемы с вашим кодом

  1. В Scala вы должны предпочесть от val до var.
  2. Всеиз ваших переменных общедоступны.Я предполагаю, что вы хотя бы хотели сделать balance приватным, поскольку у вас также есть метод getBalance.
  3. Ваш Person пример не соответствует идиоматическому стилю, поскольку вы можете просто написать его какclass Person(var personName).
0 голосов
/ 25 февраля 2019

Избавьтесь от def this() { ... }.В scala тело конструктора - это просто строки кода после объявления класса.Как это:

class Person(name: String) {
    private val id: String = name

    // ... other fields, methods, etc.
}
...