2017-08-31 18 views

Trả lời

26

Tất cả các chức năng này được sử dụng để chuyển đổi phạm vi chức năng hiện tại/biến. Chúng được sử dụng để giữ những thứ thuộc về nhau ở một nơi (chủ yếu là khởi tạo).

Dưới đây là một số ví dụ:

run - trả về bất cứ điều gì bạn muốn và tái phạm vi biến nó được sử dụng vào this

val password: Password = PasswordGenerator().run { 
     seed = "someString" 
     hash = {s -> someHash(s)} 
     hashRepetitions = 1000 

     generate() 
    } 

Các bộ tạo mật khẩu hiện đang rescoped như this và do đó chúng ta có thể thiết lập seed, hashhashRepetitions mà không sử dụng biến. generate() sẽ trả lại phiên bản Password.

apply là tương tự, nhưng nó sẽ trở lại this:

val generator = PasswordGenerator().apply { 
     seed = "someString" 
     hash = {s -> someHash(s)} 
     hashRepetitions = 1000 
    } 
val pasword = generator.generate() 

Đó là đặc biệt hữu ích như một sự thay thế cho mô hình Builder, và nếu bạn muốn tái sử dụng cấu hình nhất định.

let - chủ yếu được sử dụng để tránh kiểm tra null, nhưng cũng có thể được sử dụng để thay thế cho run. Sự khác biệt là, rằng this vẫn sẽ giống như trước đây và bạn truy cập vào biến tái scoped sử dụng it:

val fruitBasket = ... 

apple?.let { 
    println("adding a ${it.color} apple!") 
    fruitBasket.add(it) 
} 

Đoạn mã trên sẽ thêm táo để giỏ chỉ khi nó không phải là null. Cũng cần chú ý rằng it tại là không bắt buộc nữa vì vậy bạn sẽ không chạy vào một NullPointerException đây (aka bạn không cần phải sử dụng ?. để truy cập thuộc tính của nó.)

also - sử dụng nó khi bạn muốn sử dụng apply, nhưng không muốn để bóng this

class FruitBasket { 
    private var weight = 0 

    fun addFrom(appleTree: AppleTree) { 
     val apple = appleTree.pick().also { apple -> 
      this.weight += apple.weight 
      add(apple) 
     } 
     ... 
    } 
    ... 
    fun add(fruit: Fruit) = ... 
} 

Sử dụng apply đây sẽ shadow this, do đó this.weight sẽ tham khảo các táo, và không với giỏ trái cây.


Lưu ý: Tôi không biết xấu hổ lấy ví dụ from my blog

15

Có một vài điều giống như here, và here có giá trị để có một cái nhìn.

Tôi nghĩ là khi bạn cần ngắn hơn, ngắn gọn hơn trong một vài dòng, và tránh kiểm tra phân nhánh hoặc điều kiện (chẳng hạn như nếu không null, thì hãy làm điều này).

Tôi thích biểu đồ đơn giản này, vì vậy tôi đã liên kết biểu đồ tại đây. Bạn có thể xem nó từ this như được viết bởi Sebastiano Gottardo.

enter image description here

Vui lòng xem biểu đồ kèm theo giải thích của tôi bên dưới.

Concept

Tôi nghĩ nó như là một vai trò chơi cách bên trong khối mã của bạn khi bạn gọi những chức năng + cho dù bạn muốn mình trở lại (chức năng gọi chuỗi, hoặc thiết lập để gây biến, vv).

Đây là những gì tôi nghĩ.

Khái niệm Ví dụ

Hãy xem các ví dụ cho tất cả chúng ở đây

1.) myComputer.apply { } có nghĩa là bạn muốn đóng vai trò như một diễn viên chính (bạn muốn nghĩ rằng bạn máy tính), và bạn muốn bạn trở lại (máy tính) để bạn có thể làm

var crashedComputer = myComputer.apply { 
    // you're the computer, you yourself install the apps 
    // note: installFancyApps is one of methods of computer 
    installFancyApps() 
}.crash() 

Yup, bản thân bạn chỉ cần cài đặt ứng dụng, tự khắc phục và lưu lại để cho phép người khác xem và làm điều gì đó với nó.

2.) myComputer.also {} có nghĩa là bạn hoàn toàn chắc chắn rằng bạn không phải là máy tính, bạn là người ngoài muốn thực hiện điều gì đó và cũng muốn máy tính đó là kết quả trả về.

var crashedComputer = myComputer.also { 
    // now your grandpa does something with it 
    myGrandpa.installVirusOn(it) 
}.crash() 

3.) with(myComputer) { } nghĩa là bạn diễn viên chính (máy tính), và bạn không muốn mình là một kết quả trở lại.

with(myComputer) { 
    // you're the computer, you yourself install the apps 
    installFancyApps() 
} 

4.) myComputer.run { } nghĩa là bạn diễn viên chính (máy tính), và bạn không muốn mình là một kết quả trở lại.

myComputer.run { 
    // you're the computer, you yourself install the apps 
    installFancyApps() 
} 

nhưng nó khác với with { } trong một cảm giác rất tinh tế mà bạn có thể chuỗi gọi run { } như sau

myComputer.run { 
    installFancyApps() 
}.run { 
    // computer object isn't passed through here. So you cannot call installFancyApps() here again. 
    println("woop!") 
} 

Điều này là do run {} là chức năng gia hạn, nhưng không phải là with { }. Vì vậy, bạn gọi run { }this bên trong khối mã sẽ được phản ánh cho loại đối tượng người gọi. Bạn có thể xem this để có giải thích tuyệt vời về sự khác biệt giữa run {}with {}.

5.) myComputer.let { } có nghĩa là bạn là người ngoài xem máy tính và muốn thực hiện điều gì đó mà không cần phải quan tâm đến trường hợp máy tính.

myComputer.let { 
    myGrandpa.installVirusOn(it) 
} 

The Way to nhìn vào nó

tôi có xu hướng nhìn vào alsolet như cái gì đó bên ngoài, bên ngoài. Bất cứ khi nào bạn nói hai từ này, nó giống như bạn cố gắng hành động lên một thứ gì đó.let cài đặt vi rút trên máy tính này và also gặp sự cố. Vì vậy, điều này móng tay xuống một phần của việc bạn là một diễn viên hay không.

Đối với phần kết quả, rõ ràng là ở đó. also thể hiện rằng nó cũng là một thứ khác, vì vậy bạn vẫn giữ được tính khả dụng của đối tượng. Vì vậy, nó trả về nó như là một kết quả.

Mọi thứ khác liên kết với this. Ngoài ra run/with rõ ràng không quan tâm đến việc trả lại đối tượng tự quay trở lại. Bây giờ bạn có thể phân biệt tất cả chúng.

Tôi nghĩ đôi khi khi chúng ta bước ra khỏi 100% lập trình/dựa trên logic của các ví dụ, thì chúng tôi đang ở vị trí tốt hơn để khái niệm hóa mọi thứ. Nhưng điều đó phụ thuộc đúng :)

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