Phương thức trong lập trình là gì

Phương thức (

Bình phương của 5 là: 25

2, gần giống

Bình phương của 5 là: 25

3 hàm trong lập trình hướng thủ tục) trong C# là một nhóm các lệnh nhằm thực hiện một tác vụ nào đó, dùng phương thức để sử dụng lại code, dễ dàng kiểm tra và bảo trì ứng dụng. Phương thức có thể thuộc về một đối tượng lớp nào đó, hoặc không tuy nhiên khai báo phương thức thì phải khai báo trong một lớp nào đó.

Lớp là một cách tổ chức code của lập trình hướng đối tượng - ta sẽ tìm kiểu kỹ về lớp ở các phần sau.

Xem lại chương trình C# đầu tiên ở phần 1, bạn thấy có một hàm

Bình phương của 5 là: 25

4 được khai báo bên trong thân của lớp tên là

Bình phương của 5 là: 25

5, hàm này mặc dù khai báo trong lớp

Bình phương của 5 là: 25

5 nhưng có từ khóa

Bình phương của 5 là: 25

7 ở phía trước, nên nó có thể chạy mà không cần phải tạo đối tượng từ lớp

Bình phương của 5 là: 25

5

Cú pháp khai báo một phương thức cơ bản như sau:

<Access Modifiers> <return type> <name_method>(<parameters>) {

// Các câu lệnh trong phương thức  
}

  • Bình phương của 5 là: 25 9 cho biết cấp độ được phép truy cập đến hàm này (nói kỹ thi học về hướng đối tượng), có các mức độ như static internal double BinhPhuong(double number) 0, static internal double BinhPhuong(double number) 1, static internal double BinhPhuong(double number) 2, static internal double BinhPhuong(double number) 3 ... Nếu thiếu thành phần này thì mặc định coi là static internal double BinhPhuong(double number) 3 (truy cập được ở các file cùng static internal double BinhPhuong(double number) 5 cùng file code). Ngoài ra đếu cho vào từ khóa Bình phương của 5 là: 25 7 ở trước static internal double BinhPhuong(double number) 7 thì phương thức (hàm) đó gọi là PHƯƠNG THỨC TĨNH (Truy cập được mà không cần tạo đối tượng lớp), thường dùng kèm với Access Modify tên static internal double BinhPhuong(double number) 0 để tạo các hàm chức năng, tiện ích.
  • static internal double BinhPhuong(double number) 9 là kiểu trả về của hàm như using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 0 nếu hàm không có kiểu trả về thì đề từ khóa using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 1.
  • using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 2 tên của phương thức do bạn đặt.
  • using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 3 là các tham số của hàm nếu có, các tham số khai báo theo mẫu using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 4 như using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 5, nhiều tham số thì cách nhau bởi dấu using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 6.
  • Cuối cùng là phần thân hàm using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 7, trong đó chứa các câu lệnh C# mà khi hàm được gọi nó sẽ thi hành theo logic của code từ đấu đến cuối, hoặc khi gặp lệnh using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 8. Khi hàm có kiểu trả về thì trong thân hàm bắt buộc phải có câu lệnh using System; // Khai báo namespace mới tên MyLib namespace MyLib {
    // Khai báo lớp tên CS006  
    public class CS006  
    {  
        // Khai báo phương thức trong lớp  
        public static void XinChao()  
        {  
            Console.WriteLine("Xin chào C# \n");  
        }  
    }  
    
    } 9 (với using MyLib; 0 là giá trị, đối tượng, biểu thức có kiểu cùng kiểu tra về của hàm)

Ví dụ 1) Khai báo hàm (phương thức) tĩnh có tên

using MyLib;

1 trong lớp

Bình phương của 5 là: 25

5, phương thức có một tham số kiểu double, trả về kiểu double là bình phương của tham số. Sau đó gọi hàm tính bình phương của 5.

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

Chạy chương trình sẽ in ra:

Bình phương của 5 là: 25

Nhìn vào phần khai báo phương thức

using MyLib;

1, thấy không chỉ rõ

using MyLib;

4 nào, điều này có nghĩa hàm có Access Modify mặc định là

static internal double BinhPhuong(double number)

3 nghĩa là viết đầy đủ thì sẽ là:

static internal double BinhPhuong(double number)

Do có từ khóa

Bình phương của 5 là: 25

7 nó trở thành phương thức tĩnh, nên có thể gọi nó mà không cần tạo đối tượng kiểu lớp

Bình phương của 5 là: 25

5, để gọi hàm dạng này chỉ cần chỉ ra chính xác tên hàm.

Gọi phương thức trong C#

Để gọi, thi hành phương thức ta chỉ việc viết tên đầy đủ của phương thức và truyền vào tham số như ở khai báo.

Ta xem làm sao chỉ đích danh hàm khi gọi: bạn chỉ ra tên đầy đủ như sau

using MyLib;

8

Vậy để gọi được hàm

using MyLib;

1 trên cần viết

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

0 tham số truyền cho hàm là 5

Trong hàm Main trên, khi gọi BinhPhuong không cần viết đầy đủ mà chỉ cần

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

1 chúng cùng namespace nên có thể bỏ namespace, chúng cùng class nên có thể bỏ class. Hoặc đã khai báo sử dụng thư viện với từ khóa

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

2 ở đầu file, ví dụ

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

3

Tham số trong phương thức

Phương thức có thể khai báo không tham số, một hoặc nhiều tham số. Ví dụ phương thức sau không có tham số.

Tạo file

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

4, trong đó khai báo một lớp tên

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

5 có phương thức

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

6

using System; // Khai báo namespace mới tên MyLib namespace MyLib {

// Khai báo lớp tên CS006  
public class CS006  
{  
    // Khai báo phương thức trong lớp  
    public static void XinChao()  
    {  
        Console.WriteLine("Xin chào C# \n");  
    }  
}  
}

Quay trở lại phương thức Main trong

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

7, gọi nó 3 lần, kết quả có 3 dòng thông báo hiện thị.

Do gọi từ namespace khác nên đầu file

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

7 cần thêm vào

using MyLib;

Khi gọi chỉ rõ tên lớp:

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

Phương thức trong lập trình là gì

Phương thức có thể khai báo có một hoặc nhiều tham số, mỗi tham số khai bảo chỉ ra kiểu

CS006.XinChao(); CS006.XinChao(); CS006.XinChao();

9 và tên của tham số, nếu có nhiều tham số thì cách nhau bởi dấu

using System; // Khai báo namespace mới tên MyLib namespace MyLib {

// Khai báo lớp tên CS006  
public class CS006  
{  
    // Khai báo phương thức trong lớp  
    public static void XinChao()  
    {  
        Console.WriteLine("Xin chào C# \n");  
    }  
}  
}

6

Ví dụ, phương thức SoLon có hai tham số là số nguyên, trả về là số lớn hơn.

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

Trong Main gọi thử hàm này, với tham số truyền vào hàm viết đúng thứ tự

var max = CS006.SoLon(12, 40); // gọi hàm với tham số phù hợp num1 = 12, num2 = 40 Console.WriteLine(max); // Kết quả: 40

Tham số có giá trị mặc định

Nếu muốn gọi phương thức có các tham số, mà mong muốn tham số đó sẽ nhận giá trị mặc định khi không được truyền giá trị thì khi khai báo tham số khởi tạo ngay cho nó một giá trị mặc định bằng phép gán

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

1

Ví dụ, hàm tính thể tích hình hộp

// Phương thức khai báo có 3 tham số, hai tham số cuối mặc định // Nếu gọi hàm không có chỉ ra tham số cuỗi thì nó lấy giá trị mặc định này public static double TheTich(double cao, double dai = 1, double rong = 1) {

 return cao * dai * rong;  
}

Phương thức này có hai tham số nhận giá trị mặc định, bạn có thể gọi phương thức:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

0

Truyền tham số với tên

Khi gọi phương thức như các ví dụ trên, bạn truyền các tham số bằng cách điền giá trị tham số sau tên phương thức - các tham số viết đúng thứ tự khi khi nó được khai báo.

Trong

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

2 nó còn có cơ chế truyền tham số bằng cách chỉ tên và giá trị khi gọi theo cấu trúc

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

3 nếu có nhiều tham số thì cấu trúc cách nhau bởi

using System; // Khai báo namespace mới tên MyLib namespace MyLib {

// Khai báo lớp tên CS006  
public class CS006  
{  
    // Khai báo phương thức trong lớp  
    public static void XinChao()  
    {  
        Console.WriteLine("Xin chào C# \n");  
    }  
}  
}

6, điều này giúp cho việc không phải viết đúng thứ tự như khai báo, có tên khi gọi nên có vẻ dễ đọc hơn.

Thử ví dụ sau:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

1

Có thể gọi như cách thông thường

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

2

Tuy nhiên, giải phóng việc phải viết tham số theo thứ tự, bạn có thể viết:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

3

Truyền tham số tham chiếu và tham trị C#

Có hai hình thức truyền tham số cho phương thức khi nó được gọi là tham trị và tham chiếu

  • tham trị là cách thức mặc định, ta đã sử dụng ở phần trên. Có nghĩa là gán tham số bằng một biến, thì giá trị của biến được copy và sử dụng trong phương thức như biến cục bộ, còn bản thân biến bên ngoài không hề ảnh hưởng.
  • tham chiếu thì bản thân biến ở tham số sẽ được hàm sử dụng trực tiếp (tham chiếu) chứ không tạo ra một biến cục bộ trong hàm, nên nó có tác động trực tiếp đến biến này bên ngoài. Để sử dụng được using System; namespace MyLib {
    public class CS006  
    {  
        // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
        public static int SoLon(int num1, int num2)  
        {  
            int max = (num1 > num2) ? num1 : num2;  
            return max;  
        }  
    }  
    
    } 5 thì khai báo tham số ở phương thức, cũng như khi gọi cần cho thêm từ khóa using System; namespace MyLib {
    public class CS006  
    {  
        // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
        public static int SoLon(int num1, int num2)  
        {  
            int max = (num1 > num2) ? num1 : num2;  
            return max;  
        }  
    }  
    
    } 6

Tham số là các đối tượng lớp, mặc định là tham chiếu.

Khai báo

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

6 ở tham số phương thức, bắt buộc khi gọi phải sử dụng biến làm tham số chứ không được dùng giá trị.

Ví dụ tham trị:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

4

Khi sử dụng:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

5

Ta thấy, biến

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

8 bên ngoài phương thức được dùng làm tham số cho phương thức, thì giá trị của a được sao chép và gán vào biến cục bộ

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

9 của phương thức, biến

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

9 được biến đối nhưng biến

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

8 bên ngoài không ảnh hưởng.

Ví dụ tham chiếu:

Sửa lại phương thức trên như sau

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

6

Khi sử dụng:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

7

Ta thấy

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

8 sử dụng làm tham số cho phương thức, tham số

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

9 tham chiếu đến

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

8, và khi trong hàm thay đổi x, nghĩa là thay đổi

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

8 bên ngoài. (đều in ra 4)

Ngoài ra nếu gọi

var max = CS006.SoLon(12, 40); // gọi hàm với tham số phù hợp num1 = 12, num2 = 40 Console.WriteLine(max); // Kết quả: 40

6 thì sẽ lỗi, vì tham chiếu yêu cầu đối số này phải là biến.

Tham chiếu với out

Ngoài dùng từ khóa

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

6 trong khai báo tham chiếu, bạn cũng có thể thay thế nó bằng từ khóa

var max = CS006.SoLon(12, 40); // gọi hàm với tham số phù hợp num1 = 12, num2 = 40 Console.WriteLine(max); // Kết quả: 40

8, điểm khác biệt duy nhất là nếu dùng từ khóa

var max = CS006.SoLon(12, 40); // gọi hàm với tham số phù hợp num1 = 12, num2 = 40 Console.WriteLine(max); // Kết quả: 40

8 thì tham số không cần khởi tạo khi truyền cho phương thức, còn dùng

using System; namespace MyLib {

public class CS006  
{  
    // Khai báo hàm có 2 tham số kiểu int, trả trà số kiểu in  
    public static int SoLon(int num1, int num2)  
    {  
        int max = (num1 > num2) ? num1 : num2;  
        return max;  
    }  
}  
}

6 thì biến làm tham số phải khởi tạo.

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

8

Khi sử dụng:

using System; namespace CS06_Method {

class Program  
{  
    /// Tính bình phương của số thực double  
    static double BinhPhuong(double number)  
    {  
        double ketqua = number * number;  
        return ketqua;  
    }  
    static void Main(string[] args)  
    {  
        double bp = BinhPhuong(5); // Gọi hàm  
        Console.WriteLine("Bình phương của 5 là: " + bp);  
    }  
}  
}

9

Phương thức Đệ quy

Đệ quy là phương thức khai báo, trong thân của nó có gọi lại chính nó. Ví dụ cổ điển ứng dụng đệ quy là tính giai thừa của một số ví dụ

// Phương thức khai báo có 3 tham số, hai tham số cuối mặc định // Nếu gọi hàm không có chỉ ra tham số cuỗi thì nó lấy giá trị mặc định này public static double TheTich(double cao, double dai = 1, double rong = 1) {

 return cao * dai * rong;  
}

1

Bình phương của 5 là: 25

0

Bình phương của 5 là: 25

1

Đệ quy khá giống vòng lặp, bạn cần có điều kiện dừng để tránh đệ quy vô tận.

Hầu hết phương thức đệ quy có thể chuyển qua sử dụng các vòng lặp, nên cũng lưu ý nếu vòng lặp đơn giản thì nên dùng lặp.

Trong nhiều ví dụ test về hiệu năng - thì đệ quy chậm hơn việc sử dụng lặp nhiều. tham khảo