2016-08-16 16 views
5

A previous question cho biết cách đặt bộ khởi tạo tĩnh bên trong một lớp bằng cách sử dụng companion object. Tôi đang cố gắng tìm một cách để thêm một initializer tĩnh ở mức gói, nhưng có vẻ như các gói không có đối tượng đồng hành.Làm cách nào để viết trình khởi tạo tĩnh cấp gói trong Kotlin?

// compiler error: Modifier 'companion' is not applicable inside 'file' 
companion object { init { println("Loaded!") } } 
fun main(args: Array<String>) { println("run!") } 

Tôi đã thử các biến thể khác mà có thể đã thực hiện nghĩa (init ngày của riêng mình, static), và tôi biết như là một workaround tôi có thể sử dụng một throwaway val như trong

val static_init = { 
    println("ugly workaround") 
}() 

nhưng có cách nào chính xác, sạch sẽ để đạt được kết quả tương tự không?


Chỉnh sửa: Là @mfulton26's answer đề cập, không có chức năng nào như chức năng cấp gói thực sự trong JVM. Phía sau hậu trường, trình biên dịch kotlin là wrapping any free functions, including main in a class. Tôi đang cố gắng thêm bộ khởi tạo tĩnh vào rằng lớp - lớp được tạo bởi kotlin cho các hàm miễn phí được khai báo trong tệp.

+0

Tại sao không sử dụng 'main' để thực hiện việc khởi tạo? – mfulton26

+0

Vì tôi đã chọn một ví dụ đồ chơi xấu. Hãy tưởng tượng một tập tin đầy đủ các chức năng miễn phí liên quan mà tất cả phụ thuộc vào một số khởi tạo chia sẻ. Có thể cho rằng tôi chỉ có thể quấn những thứ đó vào một “vật thể” có tên, nhưng rất nhiều vẻ đẹp của kotlin thường không bị buộc phải làm những việc như thế. – Dan

+0

OK. Thật không may là tôi không biết cách nào để làm điều đó ngoài giải pháp thay thế của bạn hoặc một biến thể. ví dụ. 'val static_init = run {println (" workaround ")}' hoặc 'val static_init = object {init {println (" workaround ")}}'. – mfulton26

Trả lời

4

Hiện nay không có cách nào để thêm mã để các nhà xây dựng tĩnh được tạo ra cho các lớp tập Kotlin, tài sản duy nhất cấp cao nhất initializers đang nhận được ở đó. Điều này nghe có vẻ như một yêu cầu tính năng, do đó, bây giờ có một vấn đề để theo dõi điều này: KT-13486 Khối 'init' cấp gói

Một giải pháp thay thế khác là đặt khởi tạo đối tượng riêng tư/nội bộ cấp cao và tham chiếu đối tượng đó trong các chức năng đó phụ thuộc vào hiệu ứng của việc khởi tạo đó. Các đối tượng được khởi tạo một cách lười biếng, khi chúng được tham chiếu lần đầu tiên.

fun dependsOnState(arg: Int) = State.run { 
    arg + value 
} 

private object State { 
    val value: Int 
    init { 
     value = 42 
     println("State was initialized") 
    } 
} 
+0

Trong Kotlin 1.1, bạn có thể sử dụng Kotlin Script (.kts) để chạy mã mà không cần khai báo. Đây là loại tương tự như những gì người hỏi muốn. – Jire

3

Như bạn nói, bạn cần một tài sản với một cái gì đó mà có thể chạy trên khởi động:

val x = run { 
    println("The package class has loaded") 
} 
0

Tôi đã sử dụng thuộc tính Sao lưu ở cấp cao nhất, dưới tệp Kotlin. Kotlin Docs: Backing Properties

private var _table: Map<String, Int>? = null 
public val table: Map<String, Int> 
    get() { 
     if (_table == null) { 
      _table = HashMap() // Type parameters are inferred 
      // .... some other initialising code here 
     } 
     return _table ?: throw AssertionError("Set to null by another thread") 
    } 
+0

Nếu tất cả những gì bạn cần chỉ là một giá trị được khởi tạo lười biếng như thế này, Kotlin có một nội trang dựng sẵn cho bạn: 'val table: MutableMap bởi lazy (:: HashMap)' – Dan

Các vấn đề liên quan