我正在尝试学习 Scala Object和Class。我来自 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
类型的对象,可持久存储信息。
我还发现,根据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
}
}
问题:
“钱包”类必须声明为抽象或实现抽象 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
}
和辅助构造函数将是(通过扩展@Josh的示例),例如:
def this() {
this("Unknown Person Name")
// additional code
}
这些构造函数在here in some detail中进行了讨论,因此值得一读。
我对此感兴趣。
由于我已经声明了成员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代码中定义此。
答案 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。不过请不要这样做。
val
而不是var
。balance
设为私有,因为您也有一个getBalance
方法。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
更安全,因为类型系统和运行时将在使用该值时检查该值是否有效。
但是其他答案是正确的,如果可能的话,最好推迟创建该对象,直到键可用为止。