Scala – val, var, lazy val và def

Trong bài viết này chúng ta sẽ trình bày về các khái niệm cơ bản trong ngôn ngữ Scala. Chúng ta có thể trả lời được những câu hỏi như là var, val, def là gì? Điểm khác nhau giữa chúng là gì? Khi nào thì chúng được tính toán? Khác nhau giữa val và lazy val là gì? Những cái này là những yêu cầu cơ bản khi bạn bắt đầu học ngôn ngữ Scala

Sử dụng val

Trong Scala, val được sử dụng để định nghĩa các hằng số. val nghĩa là hằng số hoặc immutable, nghĩa là chúng ta sẽ không thể thay đổi giá trị sau khi nó được tạo ra.

scala> val name:String = "Scala"
name: String = Scala

scala> name
res2: String = Scala

scala> name = "Java"
:11: error: reassignment to val
       name = "Java"
            ^

Ở đây chúng ta có thể thấy rằng việc gán lại giá trị cho val là bị cấm. Nghĩa rằng val được dùng để định nghĩa dữ liệu immutable.

val được tính toán như thế nào?

Trong Scala, val được dùng để định nghĩa hằng số. Nó chỉ tính toán một lần, được tính toán tại thời điểm được định nghĩa. Sau khi được tính toán, nó sử dụng lại giá trị này cho tất cả các tham chiếu của nó.

Giá trị sẽ không bị tính toán trong tất cả những lần chúng ta truy cập nó.

Chúng ta sẽ hiểu rõ hơn bằng ví dụ như sau

object ValApp extends App {
  val number = { println("Constant number is initialized."); 99 }
  println("Before Accessing 'number' constant:")
  println(number + 1)
  println(number + 1)
  println(number + 1)
}

Tiếp theo chúng ta sẽ thử chạy kiểm tra kết quả

F:\>scalac ValApp.scala

F:\>scala ValApp
Constant number is initialized.
Before Accessing 'number' constant:
100
100
100

Ở đây chúng ta có thể thấy rằng hằng số number chỉ được tính toán một lần tại thời điểm chúng ta định nghĩa nó, đó là lý do vì sao nội dung của println được in ra trước khi truy cập đến biến. Mặc dù chúng ta truy cập đến hằng số number 3 lần, nó chỉ khởi tạo một lần và chỉ in ra đoạn text “Constant number is initialized.” một lần.

Sử dụng var

Trong Scala, var được sử dụng để định nghĩa các biến. var nghĩa là biến hoặc mutable, nghĩa là chúng ta có thể thay đổi giá trị của nó sau khi được tạo.

scala> var name:String = "Scala"
name: String = Scala

scala> name
res0: String = Scala

scala> name = "Java"
name: String = Java

scala> name
res1: String = Java

Ở đây có thể thấy rằng chúng ta có thể gán lại giá trị cho var. Như vậy var được sử dụng để định nghĩa dữ liệu mutable và chúng ta có thể thay đổi giá trị sau khi tạo

var được tính toán như thế nào?

var được tính toán tại thời điểm nó được định nghĩa

Nó chỉ được tính toán một lần

object VarApp extends App{
  val number = { println("Variable number is initialized."); 99 }
  println("Before Accessing 'number' variable:")
  println(number + 1)
  println(number + 1)
  println(number + 1)
}

Kết quả

F:\>scalac VarApp.scala

F:\>scala VarApp
Variable number is initialized.
Before Accessing 'number' variable:
100
100
100

Sử dụng def

Trong Scala, def được sử dụng để định nghĩa hàm hoặc phương thức. Một hàm hay phương thức có thể có hoặc không có tham số hoặc có thể có hoặc không có giá trị trả về.

scala> def add(num1:Int, num2:Int): Int = num1 + num2
add: (num1: Int, num2: Int)Int

scala> add(11,22)
res2: Int = 33

Như ví dụ trên chúng ta thấy rằng hàm hoặc phương thức chỉ tính toán khi chúng ta gọi nó

def được tính toán như thế nào?

Trong Scala, def được tính toán theo kiểu lazy. Nó sẽ không tính toán tại thời điểm được định nghĩa. Nó sẽ được tính toán bất cứ khi nào chúng ta gọi nó.

object DefApp extends App{
  def tax = {
    println("Function execution started.")
    1100
  }

  println(tax)
  println(tax)
  println(tax)
}

Kết quả

Before making a cll to Function:
Function execution started.
1100
Function execution started.
1100
Function execution started.
1100

Ở đây chúng ta có thể thấy rằng hàm hoặc phương thức chỉ được tính toán khi được gọi. Ngoài ra thì nó sẽ không tính toán gì hết.

lazy val được tính toán như thế nào?

Như chúng ta đã biết val được sử dụng định nghĩa hằng số hoặc dữ liệu immutable. Tương tự, chúng ta có thể sử dụng lazy val để định nghĩa một dữ liệu immutable.

Tuy nhiên, lazy val được tính toán lazy và chỉ một lần. Nó được tính toán chỉ một lần khi chúng ta sử dụng lần đầu tiên. Nó sẽ không được tính toán tại thời điểm định nghĩa. Nó không được tính toán mỗi khi chúng ta truy cập.

object LazyValApp extends App{
  lazy val number = { println("Constant number is initialized."); 99 }
  println("Before Accessing 'number' constant:")
  println(number + 1)
  println(number + 1)
  println(number + 1) 
}

Kết quả

Before Accessing 'number' constant:
Constant number is initialized.
100
100
100

Chúng ta sử dụng ví dụ giống như ValApp ở trên, nhưng thay đổi val thành lazy val

Chúng ta có thể nhìn thấy kết quả có sự khác biệt. Chúng ta sẽ không thấy “Constant number is initialized.”  được in ra tại thời điểm định nghĩa. Chúng ta chỉ nhìn thấy đoạn text này được in ra sau khi truy cập biến lần đầu tiên. Nó chỉ hiển thị thông báo một lần đúng không!

Chú ý rằng chúng ta không thể sử dụng lazy cho var. Nó chỉ sử dụng cho val mà thôi.

scala> lazy var a = 0
:1: error: lazy not allowed here. Only vals can be lazy
lazy var a = 0
     ^

val vs lazy val

Ở đây chúng ta sẽ thảo luận về một số điểm tương đồng và khác biệt giữa cấu trúc val và lazy val

Giống nhau giữa cấu trúc val và lazy val

  • Cả hai đều được sử dụng để định nghĩa hằng số hoặc dữ liệu immutable
  • Cả hai đều được tính toán một lần duy nhất

Khác nhau giữa cấu trúc val và lazy val

  • val được tính toán tại thời điểm định nghĩa gọi là Eagerly
  • lazy val  chỉ được tính toán khi chúng ta truy cập nó lần đầu tiên gọi là Lazy

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.