scala class 成员导致错误 "Class 'class' must either be declared abstract or implement member 'member' "
scala class members causing error "Class 'class' must either be declared abstract or implement member 'member' "
我正在努力学习 Scala Objects and Class。我来自 Java,它与 Scala 非常相似,但语法不同。
在 Java 中,我会创建一个 class,例如:
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();
这也会在Wallet
构造函数中创建一个PrivateKey
和PublicKey
,并赋值给相应的class成员。
我知道 Scala 使用了一种略有不同的方法,其中 classes 只是可实例化对象的模板,Object
s 是 Singleton
持久存储信息的类型对象。
此外,根据 this post,我发现 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
}
}
问题:
Class 'Wallet' must either be declared abstract or implement abstract
member 'publicKey: PublicKey' in 'com.simple.blockchain.Wallet
这让我很困惑。
在 Java 中,将已声明但未实例化的对象作为 class 成员通常是一个问题,因此如果我尝试添加 Companion Object,如早期 SO post 中所建议的,并遵循他们的建议:
object Wallet {
var privateKey: PrivateKey
var publicKey: PublicKey
}
我得到一个错误:
Only classes can have declared but undefined members
TL;DR
我想把Wallet
Java代码转成Scala代码,请问如何实现这个?
更新(澄清我原来的问题)
所以,答案没有反映我的实际问题(我的想法)。我会尝试澄清。
Scala 支持多种构造函数。
您会发现@Josh 提到的主要构造函数
class Person(name: String) {
var personName: String = name
}
二级构造函数将是(通过扩展@Josh 的示例)例如:
def this() {
this("Unknown Person Name")
// additional code
}
讨论了这些构造函数 here in some detail,值得一读。
我感兴趣的是这个
因为我已经声明了一个成员 privateKey
和 publicKey
,所以我想在我的 class 中声明更多的成员。并非所有这些成员都将在 class 初始化时被实例化,但稍后会在应用程序执行期间被实例化。
下文将为我上面描述的内容提供更多背景信息。我将实例化 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 代码中定义 this。
去掉 def this() { ... }
。在 scala 中,构造函数主体只是 class 声明之后的代码行。像这样:
class Person(name: String) {
private val id: String = name
// ... other fields, methods, etc.
}
您可以在伴随对象上添加应用:
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)
}
}
可以这样做,但是 it's a code smell. Suppose somebody makes an instance of your Wallet. They have to call generateKeys
before your class is really usable. If they forget and try to use the keys, they will get a runtime error or nonsensical behavior. Instead, set these in the main constructor (as ) or a factory/apply method (as ).
如果你想这样做的话
如果你真的想要一个已声明但未初始化的字段......你不能,确切地说,甚至在 Java 中也不行。在 Java 中,未初始化的字段被隐式初始化为默认值(null
对象)。您可以通过为其分配下划线 (_
) 在 Scala 中获得此行为:
var publicKey: PublicKey = _
var privateKey: PrivateKey = _
这些将被初始化为空。不过请不要这样做。
您的代码的其他问题
- 在 Scala 中,您应该更喜欢
val
而不是 var
。
- 你所有的变量都是public。我猜你至少打算将
balance
设为私有,因为你还有一个 getBalance
方法。
- 您的
Person
示例不符合惯用风格,因为您可以将其写成 class Person(var personName: String)
.
如果你需要在创建对象时没有初始化的值,最好使它们成为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
更安全,因为类型系统和运行时会在您使用时检查该值是否有效。
但其他答案是正确的,如果可能,最好推迟创建此对象,直到密钥可用。
我正在努力学习 Scala Objects and Class。我来自 Java,它与 Scala 非常相似,但语法不同。
在 Java 中,我会创建一个 class,例如:
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();
这也会在Wallet
构造函数中创建一个PrivateKey
和PublicKey
,并赋值给相应的class成员。
我知道 Scala 使用了一种略有不同的方法,其中 classes 只是可实例化对象的模板,Object
s 是 Singleton
持久存储信息的类型对象。
此外,根据 this post,我发现 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
}
}
问题:
Class 'Wallet' must either be declared abstract or implement abstract member 'publicKey: PublicKey' in 'com.simple.blockchain.Wallet
这让我很困惑。
在 Java 中,将已声明但未实例化的对象作为 class 成员通常是一个问题,因此如果我尝试添加 Companion Object,如早期 SO post 中所建议的,并遵循他们的建议:
object Wallet {
var privateKey: PrivateKey
var publicKey: PublicKey
}
我得到一个错误:
Only classes can have declared but undefined members
TL;DR
我想把Wallet
Java代码转成Scala代码,请问如何实现这个?
更新(澄清我原来的问题)
所以,答案没有反映我的实际问题(我的想法)。我会尝试澄清。
Scala 支持多种构造函数。
您会发现@Josh 提到的主要构造函数
class Person(name: String) {
var personName: String = name
}
二级构造函数将是(通过扩展@Josh 的示例)例如:
def this() {
this("Unknown Person Name")
// additional code
}
讨论了这些构造函数 here in some detail,值得一读。
我感兴趣的是这个
因为我已经声明了一个成员 privateKey
和 publicKey
,所以我想在我的 class 中声明更多的成员。并非所有这些成员都将在 class 初始化时被实例化,但稍后会在应用程序执行期间被实例化。
下文将为我上面描述的内容提供更多背景信息。我将实例化 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 代码中定义 this。
去掉 def this() { ... }
。在 scala 中,构造函数主体只是 class 声明之后的代码行。像这样:
class Person(name: String) {
private val id: String = name
// ... other fields, methods, etc.
}
您可以在伴随对象上添加应用:
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)
}
}
可以这样做,但是 it's a code smell. Suppose somebody makes an instance of your Wallet. They have to call generateKeys
before your class is really usable. If they forget and try to use the keys, they will get a runtime error or nonsensical behavior. Instead, set these in the main constructor (as
如果你想这样做的话
如果你真的想要一个已声明但未初始化的字段......你不能,确切地说,甚至在 Java 中也不行。在 Java 中,未初始化的字段被隐式初始化为默认值(null
对象)。您可以通过为其分配下划线 (_
) 在 Scala 中获得此行为:
var publicKey: PublicKey = _
var privateKey: PrivateKey = _
这些将被初始化为空。不过请不要这样做。
您的代码的其他问题
- 在 Scala 中,您应该更喜欢
val
而不是var
。 - 你所有的变量都是public。我猜你至少打算将
balance
设为私有,因为你还有一个getBalance
方法。 - 您的
Person
示例不符合惯用风格,因为您可以将其写成class Person(var personName: String)
.
如果你需要在创建对象时没有初始化的值,最好使它们成为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
更安全,因为类型系统和运行时会在您使用时检查该值是否有效。
但其他答案是正确的,如果可能,最好推迟创建此对象,直到密钥可用。