导致错误的Scala类成员“类'class'必须声明为抽象或实现成员'member'”

时间:2019-02-24 21:11:16

标签: java scala class functional-programming member

我正在尝试学习 Scala ObjectClass。我来自 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构造函数中创建一个PublicKeyWallet并将其分配给相应的类成员。

我知道 Scala 使用的方法略有不同,其中类只是可实例化对象的模板,而ObjectSingleton类型的对象,可持久存储信息。

我还发现,根据this postObjectClass文件中经常用作伴侣对象

使用上面的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
  }
}

问题:

  

“钱包”类必须声明为抽象或实现抽象   com.simple.blockchain.Wallet中的成员'publicKey:PublicKey'

现在这让我感到困惑。

Java 中,将尚未实例化的对象声明为类成员通常会是一个问题,因此,如果我尝试按照前面的建议添加 Companion对象所以张贴并遵循他们的建议:

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

我得到一个错误:

  

只有类可以声明但未定义的成员

TL; DR

我想将Wallet Java 代码转换为 Scala 代码,我该如何实现?


更新(以澄清我的原始问题)

因此,答案不能反映我的实际问题(我的初衷)。我会尝试澄清。

Scala支持各种构造函数。

您会发现@Josh here

提到的主要构造函数
class Person(name: String) {
    var personName: String = name
}

和辅助构造函数将是(通过扩展@Jos​​h的示例),例如:

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

这些构造函数在here in some detail中进行了讨论,因此值得一读。

我对此感兴趣。

由于我已经声明了成员privateKeypublicKey,所以我希望在班级中声明更多成员。在初始化类时,并非所有这些成员都将被实例化,但在应用程序执行期间将被实例化。

下面的内容将为我上述内容提供更多背景信息。我将实例化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 :(得分:3)

摆脱def this() { ... }。在scala中,构造函数主体只是类声明之后的代码行。像这样:

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

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

答案 1 :(得分:2)

您可以在随播对象上添加一个应用:

class User
{    
    public function boards()
    {
        return $this->belongsToMany('App\Board', 'memberships', 'user_id', 'board_id');
    }
}

class Board
{    
    public function members()
    {
        return $this->belongsToMany('App\User', 'memberships', 'board_id', 'user_id');
    }
}

答案 2 :(得分:2)

可以这样做,但是it's a code smell。假设有人制作了您的电子钱包实例。在您的课程真正可用之前,他们必须致电generateKeys。如果他们忘记了并尝试使用这些键,则会收到运行时错误或无意义的行为。而是在主构造函数中将其设置为Josh suggests,在工厂/应用方法中将其设置为Andy suggests

但是我喜欢反模式和代码气味!

如果您真的想拥有一个已声明但未初始化的字段...甚至在Java中也无法做到。在Java中,未初始化的字段被隐式初始化为默认值(对象为null)。您可以在Scala中通过为其分配下划线(_)来获得此行为:

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

这些将初始化为null。不过请不要这样做。

您的代码存在其他问题

  1. 在Scala中,您应该更喜欢val而不是var
  2. 所有变量都是公共变量。我猜您至少打算将balance设为私有,因为您也有一个getBalance方法。
  3. 您的Person示例未遵循惯用风格,因为您可以将其编写为class Person(var personName)

答案 3 :(得分:2)

如果您需要创建对象时未初始化的值,则最好使它们为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更安全,因为类型系统和运行时将在使用该值时检查该值是否有效。

但是其他答案是正确的,如果可能的话,最好推迟创建该对象,直到键可用为止。