Từ khóa "mới" trong Scala


93

Tôi có một câu hỏi rất đơn giản - khi nào chúng ta nên áp dụng từ khóa mới khi tạo các đối tượng trong Scala? Có phải khi chúng ta cố gắng khởi tạo các đối tượng Java chỉ?

Câu trả lời:


144

Sử dụng newtừ khóa khi bạn muốn tham chiếu đến classphương thức khởi tạo của riêng mình:

class Foo { }

val f = new Foo

Bỏ qua newnếu bạn đang đề cập đến applyphương thức của đối tượng đồng hành :

class Foo { }
object Foo {
    def apply() = new Foo
}

// Both of these are legal
val f = Foo()
val f2 = new Foo

Nếu bạn đã tạo một lớp trường hợp:

case class Foo()

Scala bí mật tạo một đối tượng đồng hành cho bạn, biến nó thành thế này:

class Foo { }
object Foo {
    def apply() = new Foo
}

Vì vậy, bạn có thể làm

f = Foo()

Cuối cùng, hãy nhớ rằng không có quy tắc nào nói rằng apply phương thức đồng hành phải là một proxy cho hàm tạo:

class Foo { }
object Foo {
    def apply() = 7
}

// These do different things
> println(new Foo)
test@5c79cc94
> println(Foo())
7

Và, vì bạn đã đề cập đến các lớp Java: vâng - Các lớp Java hiếm khi có các đối tượng đồng hành với một applyphương thức, vì vậy bạn phải sử dụng newvà hàm tạo của lớp thực tế.


1
Một lớp Java không bao giờ có thể có một đối tượng đồng hành. Nó có thể có một đối tượng có thể hoạt động như một Nhà máy cho lớp Java - nhưng đối tượng này không phải là đối tượng đồng hành của nó.
kiritsuku

@Antoras Vì các lớp Scala biên dịch sang mã bytecode của Java và có thể được phân phối ở dạng đã biên dịch, Scala có thể cho biết sự khác biệt giữa đồng hành Scala thực tế và lớp có tên Foo $ với thành viên MODULE $ tĩnh không?
Owen

1
Tôi nghĩ rằng scalac có thể khác biệt điều này vì nó được chỉ định rằng một đối tượng đồng hành phải được khai báo trong cùng một tệp với lớp đồng hành của nó. Vì "thuộc tính" đồng hành chỉ tồn tại trong Scala và không tồn tại trên thang đo cấp Bytecode nên phải kiểm tra mã Scala chứ không phải Bytecode để đảm bảo rằng thông số kỹ thuật được tuân theo.
kiritsuku

1
Bất kỳ ví dụ nào về các lớp Java KHÔNG sử dụng từ khóa mới trong Scala?
Bober 02

Ngoài ra, các phương thức trên đối tượng đồng hành cũng sẽ được truy cập thông qua các phương thức tĩnh trên lớp và điều đó sẽ không bao giờ xảy ra với các lớp java mà bạn xác định "đồng hành" sau này.
drexin

16

Có phải khi chúng ta cố gắng khởi tạo các đối tượng java chỉ?

Không có gì. Có hai trường hợp chung khi bạn bỏ qua newtrong scala. Với các đối tượng singleton (thường được sử dụng để lưu trữ các hàm tĩnh và như một loại nhà máy tương tự như những gì bạn có thể thấy trong java):

scala> object LonelyGuy { def mood = "sad" }
defined module LonelyGuy

scala> LonelyGuy
res0: LonelyGuy.type = LonelyGuy$@3449a8

scala> LonelyGuy.mood
res4: java.lang.String = sad

Với các lớp trường hợp (thực tế, bên dưới có lớp + đối tượng = mẫu đồng hành , ví dụ: có lớp và đối tượng có cùng tên):

scala> case class Foo(bar: String) 
defined class Foo


scala> Foo("baz")
res2: Foo = Foo(baz)

Vì vậy, khi bạn làm việc với một lớp đơn giản, các quy tắc cũng giống như với Java.

scala> class Foo(val bar: String) 
defined class Foo

scala> new Foo("baz")
res0: Foo = Foo@2ad6a0

// will be a error 
scala> Foo("baz")
<console>:8: error: not found: value Foo
       Foo("baz")

Phần thưởng, có một lớp ẩn danh trong scala, có thể được xây dựng như thế này:

scala> new { val bar = "baz" }
res2: java.lang.Object{val bar: java.lang.String} = $anon$1@10ee5b8

scala> res2.bar
res3: java.lang.String = baz

1
Bạn ổn chứ?
Jacob B

0

Có phải khi chúng ta cố gắng khởi tạo các đối tượng Java chỉ?

Với Scala 3 (sẽ được phát hành vào giữa năm 2020, tám năm sau), dựa trên Dotty : không bao giờ.

Scala 3 sẽ giảm " new", như trong chuỗi này

Các ứng dụng của người tạo cho phép sử dụng cú pháp gọi hàm đơn giản để tạo các thể hiện của một lớp, ngay cả khi không có phương thức áp dụng nào được triển khai.

Thí dụ:

class StringBuilder(s: String) {
   def this() = this(s)
}

StringBuilder("abc")  // same as new StringBuilder("abc")
StringBuilder()       // same as new StringBuilder()

Ứng dụng của người tạo khái quát hóa một chức năng được cung cấp cho đến nay chỉ dành cho các lớp trường hợp, nhưng cơ chế đạt được điều này hơi khác một chút.
Thay vì một phương thức áp dụng được tạo tự động, chúng tôi thêm một cách diễn giải khả thi mới cho một lệnh gọi hàm f(args).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.