Chuyển đến nội dung chính

Những điều cơ bản về Hàm và Phương thức trong Scala

Tìm hiểu những điều cơ bản về phương thức, đối số có tên, giá trị tham số mặc định, đối số biến đổi cùng các loại hàm khác nhau.
Đã cập nhật 5 thg 10, 2026  · 10 phút đọc

Khám phá cùng AI

ChatGPTClaudePerplexity

Quan tâm đến việc học thêm về Scala? Hãy tham gia khóa học Giới thiệu về Scala của DataCamp.

Scala là một ngôn ngữ lập trình hàm, trong đó có cả hàm như giá trị hạng nhất lẫn phương thức, với nhiều điểm tương đồng và khác biệt. Cả hàm và phương thức đều là khối mã có thể tái sử dụng, dùng để gom phần mã lặp lại vào một chỗ, cho phép gọi để thực hiện một tác vụ cụ thể. Chúng cũng giúp mã dễ gỡ lỗi và sửa đổi hơn.

Tuy nhiên, hàm là một đối tượng được gán cho biến, còn phương thức bắt đầu với từ khóa 'def' theo sau là tên phương thức, danh sách tham số, thân phương thức và giá trị trả về.

Khai báo và định nghĩa phương thức

Cú pháp khai báo và định nghĩa phương thức trong Scala như sau:

def 'method_name' ('parameters':'return_type_parameters') : ('return_type_of_method') = {
    'method_body'
     return 'value'
}

Một phương thức trong Scala bắt đầu với các phần sau:

  1. 'def': từ khóa dùng để khai báo phương thức.
  2. 'method_name': tên phương thức, viết theo kiểu lower camel case.
  3. 'parameters': là các tham số của phương thức; có thể không có tham số hoặc chỉ có một, nhưng nếu có nhiều hơn một thì phân tách bằng dấu phẩy.
  4. 'return_type_of_parameters': cần khớp với kiểu dữ liệu của 'parameters_list' và là bắt buộc.
  5. 'return_type_of_method': là tùy chọn; mặc định trả về 'Unit', nhưng có thể trả về giá trị với từ khóa 'return'.
  6. Ký hiệu gán ('='): là tùy chọn; nếu dùng sẽ gán giá trị trả về, nếu không dùng thì phương thức sẽ không trả về gì.
  7. 'method_body': khối mã nằm trong ngoặc nhọn '{}' chứa logic, tác vụ hoặc thao tác cần thiết.
  8. return: từ khóa dùng để trả về giá trị cần thiết và cũng kết thúc chương trình, nhưng hiếm khi dùng trong Scala.

Gọi phương thức

Cú pháp gọi phương thức trong Scala như sau:

    method_name(arguments)

Việc gọi phương thức thực hiện nhanh chóng bằng 'method_name', là tên của phương thức tương ứng bạn muốn gọi, kèm theo các đối số được truyền vào.

Phương thức với đối số có tên

Phương thức với đối số có tên cho phép truyền đối số khớp với tham số của phương thức trong lúc gọi, trong đó mỗi đối số được ghép lần lượt với từng tham số. Dưới đây là ví dụ về truyền đối số cùng với phần khai báo, định nghĩa hàm và cách gọi phương thức:

object calculateResult {
      def funSub(x:Int, y:Int) : Int =
   {

       var diff:Int = 0
       diff = x - y

       // return value
       return diff
   }
   def main(args: Array[String]) {

      // Function call
      println("Difference of the value is: " + funSub(8,6));
      println("Difference of the value is " + funSub(y=6,x=8));
   }
}

Chương trình trên cho kết quả:
Difference of the value is: 2
Difference of the value is: 2

Chương trình trên có một đối tượng 'calculateResult', bên trong chứa phương thức 'funSub' với hai tham số x và y, đều có kiểu trả về là 'Int', và kiểu trả về tổng thể của phương thức là 'Int'. Sau đó là một câu lệnh gán để gán giá trị trả về. Dấu ngoặc nhọn chỉ phần bắt đầu của thân phương thức, nơi biến 'diff' được khởi tạo với giá trị ban đầu là 0. Lời gọi phương thức 'funSub(8,6)' trong hàm main ghép 8 cho 'x' và 6 cho 'y', thực hiện phép trừ, trả về giá trị của 'diff' và cuối cùng in ra. Tương tự, 'funSub(x=8,y=6)' ghép 6 cho 'y' và 8 cho 'x' khi gọi phương thức, thứ tự không quan trọng; thao tác tương tự được thực hiện, giá trị được trả về và in kết quả.

Giá trị tham số mặc định

Bạn có thể chỉ định giá trị mặc định cho các tham số của phương thức bằng cách khởi tạo giá trị tương ứng và có thể bỏ trống phần truyền đối số khi gọi phương thức.

object calculateResult {
      def funSub(x:Int=9, y:Int=6) : Int =
   {

       var diff:Int = 0
       diff = x - y

       // return value
       return diff
   }
   def main(args: Array[String]) {

      // Function call
    print( "The final value is: " + funSub() );

   }
}

Chương trình trên cho kết quả:
The final value is: 3

Bạn có thể thấy chương trình trên có đối tượng 'calculateResult' và bên trong có phương thức 'funSub' với tham số x và y đều có kiểu trả về là 'Int', kiểu trả về tổng thể của phương thức là 'Int', tiếp theo là câu lệnh gán sẽ gán giá trị trả về. Dấu ngoặc nhọn chỉ phần bắt đầu của thân phương thức, nơi biến 'diff' được khởi tạo với giá trị ban đầu là 0. Lời gọi phương thức được thực hiện trong hàm main, nơi 'funSub()' được gọi và khởi tạo x = 9, y = 6, thực hiện phép tính, trả về 'diff' và in ra.

Đối số độ dài biến đổi

Đối số độ dài biến đổi là những đối số có thể nhận số lượng tham số tùy ý do người dùng hoặc client truyền vào. Tham số cuối cùng trong phương thức được khai báo với '*' để chỉ rằng có thể lặp lại.

object variableArgument {
    def main(args: Array[String]) {
       printAll("Scala", "is", "great")
    }

    def printAll(strings: String*) {
        var i : Int = 0;

      for( value <- strings ){
         println(value);
         i = i + 1;
      }
    }
}

Chương trình trên cho kết quả:
Scala
is
great

Bạn có thể thấy chương trình trên có đối tượng 'variableArgument' với phương thức 'printAll' nơi đối số độ dài biến đổi 'String*' được định nghĩa ở cuối, và khi gọi phương thức có thể truyền vào một danh sách chuỗi. Danh sách chuỗi được truyền vào sẽ được lặp qua và hiển thị kết quả trong hàm chính.

Hàm đệ quy

Đệ quy là kỹ thuật dùng trong lập trình hàm, trong đó bài toán được giải bằng cách lặp lại việc chia nhỏ thành các bài toán con có bản chất tương tự bài toán gốc. Các bài toán nhỏ hơn được giải trước và lời giải của chúng được dùng để tìm lời giải cho bài toán ban đầu. Vì vậy, đây là cách tiếp cận chia để trị hoặc giảm dần để trị, giúp mã sạch và thanh lịch. Khi viết hàm đệ quy, cần cân nhắc nghiêm ngặt hai điểm sau:

  • Trường hợp cơ sở (base case): Có thể có nhiều hơn một trường hợp cơ sở trong một hàm; nếu không xác định được có thể dẫn đến đệ quy vô hạn. Nó cần có lời giải, tức dạng kết quả đơn giản có thể đạt được mà không cần đệ quy.
  • Trường hợp đệ quy: Trường hợp áp dụng hàm đệ quy, tức các lời gọi đệ quy được thực hiện. Cốt lõi là ở mỗi lần gọi đệ quy, kích thước bài toán phải giảm xuống, tức bài toán được chia thành các bài toán con nhỏ hơn cho đến khi chạm đến trường hợp cơ sở. Cuối cùng, bạn kết hợp các lời giải để giải quyết bài toán chính, đó là cách tiếp cận chia để trị.

Giai thừa của một số bất kỳ là n! Có thể biểu diễn toán học như sau:

n! = n.(n-1).(n-2)...3.2.1

Ta cũng có thể viết (n-1).(n-2)...3.2.1 là (n-1)!. Vậy giai thừa của một số bất kỳ luôn là n.(n-1)!

Bây giờ bạn có thể xem cách giải bài toán bằng đệ quy dưới đây.

object factorialDemo {
   def main(args: Array[String]) {
      for (i <- 1 to 5)
         println( "Factorial of " + i + ": = " + factorial(i) )
   }

   def factorial(n: Int): Int = {  
      if (n <= 1)
         return 1  
      else    
      return n * factorial(n - 1)
   }
}

Chương trình trên cho kết quả:
Factorial of 1: = 1
Factorial of 2: = 2
Factorial of 3: = 6
Factorial of 4: = 24
Factorial of 5: = 120

Bạn có thể thấy có một đối tượng tên 'factorialDemo' với hàm 'main' chứa một vòng lặp lặp lại năm lần và có lời gọi tới hàm 'factorial' nơi hàm đệ quy gọi chính nó, tức là n cho đến năm lần. Nó dừng ở trường hợp cơ sở khi n nhỏ hơn hoặc bằng 1, sau đó trả về kết quả và in ra.

Hàm vô danh

Hàm vô danh là những định nghĩa hàm gọn nhẹ không có tên, còn được gọi là function literal trong Scala.

Cú pháp kèm ví dụ cho hàm vô danh như sau:

  • Cú pháp đầu tiên và ví dụ cho hàm vô danh là:

Cú pháp:

('first_variable':'data_type', 'second_variable':'data_type') => "certain_expression"

Ví dụ:

(var1:String:var2:String) => var1 + var2

HOẶC

  • Cú pháp thứ hai và ví dụ cho hàm vô danh là:

Cú pháp:

 (_:'data_type')operator(_'data_type')

Ví dụ:

 (_:String)+(_:String)

Cú pháp đầu tiên cho thấy biểu thức sau "=>" được tính ra một giá trị cụ thể, còn danh sách biến trước "=>" được dùng để đánh giá biểu thức đó.

Cú pháp thứ hai ở trên hoạt động như một ký tự giữ chỗ, chấp nhận giá trị như một ký tự 'wild card' chỉ một lần, sau đó toán tử sẽ được áp dụng giữa chúng.

Dưới đây là một ví dụ về hàm vô danh:

 object anonymousDemo  
{
    def main(args: Array[String])  
    {


        var function1 = (var1:Int, var2:Int) => var1 + var2
        var function2 = (_:Int) + (_:Int)

        // function call
        println(function1(5, 5))
        println(function2(7, 3))
    }
}
Initializing Scala interpreter ...



Spark Web UI available at http://DESKTOP-03TH7J0:4040
SparkContext available as 'sc' (version = 2.4.3, master = local[*], app id = local-1566986265958)
SparkSession available as 'spark'




<console>:10: error: unbound placeholder parameter

        var function2 = {_:Int} + {_:Int}

                         ^

<console>:10: error: unbound placeholder parameter

        var function2 = {_:Int} + {_:Int}

                                   ^

Chương trình trên cho kết quả:
10
10

Bạn có thể thấy đối tượng có tên 'anonymousDemo' với hàm 'main' chứa hai hàm vô danh. Chúng khác nhau về cú pháp nhưng cho cùng kết quả, trong đó 'function1' đánh giá bằng cách nhận tham số từ lần gọi hàm khi được gọi—truyền vào các giá trị 5 và 5, in ra kết quả 10; còn 'function2' cũng được gọi với 7 và 3, nhận giá trị một lần, chấp nhận bất kỳ 'Integer' hợp lệ nào. Trong trường hợp này, thực hiện phép cộng và in kết quả.

Kết luận

Chúc mừng bạn đã hoàn thành việc đọc hướng dẫn này.

Còn nhiều chủ đề nâng cao trong Scala như hàm bậc cao, hàm lồng nhau, currying, v.v.

Tham khảo:
TOUR OF SCALA BASICS
Scala | Functions – Basics
Scala - Functions
Anonymous Functions in Scala

Hãy xem khóa học Giới thiệu về Scala của DataCamp.

Chủ đề
Scala

Tìm hiểu thêm về Scala

Khóa học

Introduction to Scala

3 giờ
27.2K
Begin your journey with Scala, a popular language for scalable applications and data engineering infrastructure.
Xem chi tiếtRight Arrow
Bắt Đầu Khóa Học
Xem thêmRight Arrow
Liên quan

blog

Claude Opus 4.6: Tính năng, Điểm chuẩn, Bài kiểm tra thực hành và hơn thế nữa

Mô hình mới nhất của Anthropic dẫn đầu ở mã hóa tác tử và lập luận phức tạp. Thêm vào đó, nó có cửa sổ ngữ cảnh 1M.
Matt Crabtree's photo

Matt Crabtree

10 phút

Xem ThêmXem Thêm