在 Scala 中,主要构造函数是类的主体。类名后跟一个参数列表,它们是构造函数的参数。(与任何函数一样,可以省略空参数列表。)
class Foo(x: Int, y: String) { val xy: String = y * x /* now xy is a public member of the class */ } class Bar { ... }
除非通过val关键字标记为实例成员,否则在其构造函数主体之外无法访问实例的构造参数:
class Baz(val z: String) // Baz 没有其他成员或方法,因此可以省略主体 val foo = new Foo(4, "ab") val baz = new Baz("I am a baz") foo.x // 不会编译:x 不是 Foo 的成员 foo.xy // returns "abababab": xy is a member of Foo baz.z // returns "I am a baz": z is a member of Baz val bar0 = new Bar val bar1 = new Bar() // 构造函数括号在这里是可选的
实例化对象的实例时应该执行的任何操作都直接写入类的主体中:
class DatabaseConnection (host: String, port: Int, username: String, password: String) { /* first connect to the DB, or throw an exception */ private val driver = new AwesomeDB.Driver() driver.connect(host, port, username, password) def isConnected: Boolean = driver.isConnected ... }
请注意,将尽可能少的副作用放入构造函数被认为是一种很好的做法;而不是上面的代码,应该考虑拥有connect和disconnect方法,以便消费者代码负责调度 IO。
一个类可能有额外的构造函数,称为“辅助构造函数”。这些由构造函数定义以 形式定义def this(...) = e,其中e必须调用另一个构造函数:
class Person(val fullName: String) { def this(firstName: String, lastName: String) = this(s"$firstName $lastName") } // 用法: new Person("Grace Hopper").fullName // 格蕾丝·霍珀归来 new Person("Grace", "Hopper").fullName // 格蕾丝·霍珀归来
这意味着每个构造函数可以有不同的修饰符:只有一些可能是公开的:
class Person private(val fullName: String) { def this(firstName: String, lastName: String) = this(s"$firstName $lastName") } new Person("Ada Lovelace") // 不会编译 new Person("Ada", "Lovelace") // 编译
通过这种方式,您可以控制使用者代码如何实例化类。