Thư viện chuẩn của Kotlin chứa một số hàm với mục đích duy nhất là thực thi một khối mã trong ngữ cảnh của một đối tượng. Khi bạn gọi một hàm như vậy trên một đối tượng có biểu thức lambda được cung cấp, nó sẽ tạo thành một phạm vi tạm thời. Trong phạm vi này, bạn có thể truy cập đối tượng mà không cần tên của nó. Các chức năng như vậy được gọi là chức năng phạm vi. Có năm người trong số họ. let
, run
, with
, apply
và also
Về cơ bản, các chức năng này làm giống nhau. thực thi một khối mã trên một đối tượng. Điều khác biệt là làm thế nào đối tượng này trở nên khả dụng bên trong khối và kết quả của toàn bộ biểu thức là gì
Đây là cách sử dụng điển hình của hàm phạm vi
lớp dữ liệu Person[var name. Chuỗi, var tuổi. thành phố int, var. Chuỗi] { fun moveTo[newCity. String] { city = newCity } fun incrementAge[] { age++ } } fun main[] { //sampleStart Person["Alice", 20, "Amsterdam"]. hãy để { println[nó] nó. moveTo["London"] nó. incrementAge[] println[it] } //sampleEnd }
Nếu bạn viết giống như vậy mà không có let
, bạn sẽ phải giới thiệu một biến mới và lặp lại tên của nó bất cứ khi nào bạn sử dụng nó
lớp dữ liệu Person[var name. Chuỗi, var tuổi. thành phố int, var. Chuỗi] { fun moveTo[newCity. String] { city = newCity } fun incrementAge[] { age++ } } fun main[] { //sampleStart val alice = Person["Alice", 20, "Amsterdam"] println[alice] alice. moveTo["London"] alice. incrementAge[] println[alice] //sampleEnd }
Các hàm phạm vi không giới thiệu bất kỳ khả năng kỹ thuật mới nào, nhưng chúng có thể làm cho mã của bạn ngắn gọn và dễ đọc hơn
Do tính chất tương tự của các hàm phạm vi, việc chọn một hàm phù hợp cho trường hợp của bạn có thể hơi phức tạp. Sự lựa chọn chủ yếu phụ thuộc vào ý định của bạn và tính nhất quán của việc sử dụng trong dự án của bạn. Dưới đây chúng tôi sẽ cung cấp các mô tả chi tiết về sự khác biệt giữa các hàm phạm vi và các quy ước về cách sử dụng chúng
lựa chọn chức năng
Để giúp bạn chọn chức năng phạm vi phù hợp với mục đích của mình, chúng tôi cung cấp bảng về sự khác biệt chính giữa chúng
Chức năng
tham chiếu đối tượng
Giá trị trả về
Là chức năng mở rộng
let
it
kết quả lambda
Đúng
run
this
kết quả lambda
Đúng
run
-
kết quả lambda
KHÔNG. được gọi mà không có đối tượng bối cảnh
with
this
kết quả lambda
KHÔNG. lấy đối tượng ngữ cảnh làm đối số
apply
this
đối tượng bối cảnh
Đúng
also
it
đối tượng bối cảnh
Đúng
Thông tin chi tiết về sự khác biệt được cung cấp trong các phần dành riêng bên dưới
Dưới đây là một hướng dẫn ngắn để chọn các chức năng phạm vi tùy thuộc vào mục đích dự kiến
Thực thi lambda trên các đối tượng không null.
let
Giới thiệu một biểu thức dưới dạng một biến trong phạm vi cục bộ.
let
cấu hình đối tượng.
apply
Cấu hình đối tượng và tính toán kết quả.
run
Chạy các câu lệnh trong đó một biểu thức được yêu cầu. không mở rộng
run
hiệu ứng bổ sung.
also
Gọi hàm nhóm trên một đối tượng.
with
Các trường hợp sử dụng của các chức năng khác nhau chồng lên nhau, do đó bạn có thể chọn các chức năng dựa trên các quy ước cụ thể được sử dụng trong dự án hoặc nhóm của bạn
Mặc dù các hàm phạm vi là một cách làm cho mã ngắn gọn hơn, tránh lạm dụng chúng. nó có thể làm giảm khả năng đọc mã của bạn và dẫn đến lỗi. Tránh lồng các hàm phạm vi và cẩn thận khi xâu chuỗi chúng. rất dễ nhầm lẫn về đối tượng bối cảnh hiện tại và giá trị của this
hoặc it
sự khác biệt
Bởi vì các hàm phạm vi đều khá giống nhau về bản chất, điều quan trọng là phải hiểu sự khác biệt giữa chúng. Có hai sự khác biệt chính giữa mỗi chức năng phạm vi
Cách tham chiếu đến đối tượng bối cảnh
Giá trị trả về
đối tượng ngữ cảnh. cái này hoặc nó
Bên trong lambda của một hàm phạm vi, đối tượng bối cảnh có sẵn bằng một tham chiếu ngắn thay vì tên thực của nó. Mỗi chức năng phạm vi sử dụng một trong hai cách để truy cập đối tượng bối cảnh. dưới dạng lambda [this
] hoặc dưới dạng đối số lambda [it
]. Cả hai đều cung cấp các khả năng giống nhau, vì vậy chúng tôi sẽ mô tả ưu và nhược điểm của từng loại cho các trường hợp khác nhau và đưa ra các đề xuất về việc sử dụng chúng
fun main[] { val str = "Xin chào" // str này. run { println["Độ dài chuỗi. $length"] //println["Độ dài chuỗi. ${cái này. length}"] // làm tương tự } // nó str. let { println["Chuỗi có độ dài là ${it. chiều dài}"] } }
cái này
run
, with
và apply
đề cập đến đối tượng ngữ cảnh dưới dạng bộ thu lambda - theo từ khóa this
. Do đó, trong lambdas của họ, đối tượng có sẵn như trong các hàm lớp thông thường. Trong hầu hết các trường hợp, bạn có thể bỏ qua this
khi truy cập các thành viên của đối tượng nhận, làm cho mã ngắn hơn. Mặt khác, nếu bỏ qua this
, có thể khó phân biệt giữa các thành phần nhận và các đối tượng hoặc chức năng bên ngoài. Vì vậy, nên sử dụng đối tượng ngữ cảnh làm đối tượng nhận [this
] cho lambda chủ yếu hoạt động trên các thành viên đối tượng. gọi các chức năng của nó hoặc gán các thuộc tính
lớp dữ liệu Person[var name. Chuỗi, var tuổi. Int = 0, var thành phố. String = ""] fun main[] { //sampleStart val adam = Person["Adam"]. áp dụng { tuổi = 20 // giống như thế này. tuổi = 20 thành phố = "London" } println[adam] //sampleEnd }
Nó
Đổi lại, let
và also
có đối tượng ngữ cảnh làm đối số lambda. Nếu tên đối số không được chỉ định, đối tượng được truy cập bằng tên mặc định ngầm định it
. it
ngắn hơn this
và các biểu thức với it
thường dễ đọc hơn. Tuy nhiên, khi gọi các hàm hoặc thuộc tính của đối tượng, bạn không có sẵn đối tượng như this
. Do đó, có đối tượng ngữ cảnh là it
sẽ tốt hơn khi đối tượng chủ yếu được sử dụng làm đối số trong các lệnh gọi hàm. it
cũng tốt hơn nếu bạn sử dụng nhiều biến trong khối mã
nhập kotlin. ngẫu nhiên. Niềm vui ngẫu nhiên writeToLog[tin nhắn. Chuỗi] { println["THÔNG TIN. $message"] } fun main[] { //sampleStart fun displaySubstringPosition[input. Chuỗi, phụ. Chuỗi] { chỉ số val = đầu vào. indexOf[sub] if [index >= 0] { println["Chuỗi con $sub được tìm thấy trong $input. "] println["Vị trí bắt đầu của nó là $index. "] } } displaySubstringPosition["010000011", "11"] displaySubstringPosition["010000011", "12"] //sampleEnd }