[Scala] - day 3 : Function trong Scala

Function được hiểu là 1 khối code thực hiện 1 logic nào đó và có thể sử dụng lại.Khái niệm này tương tư như các ngôn ngữ khác.
Function trong Scala có thể được mô tả bằng 2 tính chất :
- Được đặt tên
- Là 1 hay nhiều expression có thể tái sử dụng.
Function trong scala mang nhiều đặc điểm của Functional programming,tuy nhiên trong bài này tôi sẽ không giải thích về Functional programming,nó sẽ là bài tập của bạn,kết thúc bài viết này bạn thử tìm hiểu về Functional programming và đối chiếu lại với những tính chất tôi liệt kê dưới đây.

I - Cách khai báo Function trong Scala

Input-less Function (không có input)

Syntax:
def <identifier> = <expression>
 Tương tự như bạn khai báo 1 value hay 1 variable ,bạn thấy có gì khác ở đây? chúng ta có từ khoá "def".
Ví dụ :
scala> def chaoHoai = "Chào Hoài PT"
chaoHoai: String
scala> chaoHoai
res0: String = Chào Hoài PT
 1 cách khác để bạn khai báo 1 function không có input đó là dùng 1 cặp dấu đóng mở tròn rỗng ()  - Empty Parentheses.Tôi viết lại function trên với Empty Parentheses :
scala> def chaoHoai2() = "Chào Hoài PT"
chaoHoai2: ()String
Bạn thấy điều gì khác biệt ở kết quả không , điều đó dẫn điến viêc sử dụng cũng khác nhau :

scala> chaoHoai2()
res1: String = Chào Hoài PT
scala> chaoHoai2
res2: String = Chào Hoài PT
scala> chaoHoai()
<console>:12: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
chaoHoai()
               ^

Function with a Return Type (function trả về kiểu cố định)

Như bạn thấy ở trên ,nếu bạn không set kiểu trả về cho function Scala sẽ tự tính toán và set cho bạn, trong thực tế bạn nên tự set kiểu cho function mình viết, điều đấy khiến cho code của bạn rõ ràng hơn và tránh được nhiều sai sót ngoài ý muốn.
Syntax:
def <identifier>: <type> = <expression>
Ví dụ :
scala> def kieuTraVeLaString : String = "đây là 1 String"
kieuTraVeLaString: String
scala> def kieuTraVeLaInt : Int = 100
kieuTraVeLaInt: Int

Định nghĩa đầy đủ 1 Function 

Syntax:
def <identifier>(<identifier>: <type>[, ... ]): <type> = <expression>
Ví dụ :
scala> def cong2So(soThuNhat: Int , soThuHai: Int) : Int = soThuNhat + soThuHai
cong2So: (soThuNhat: Int, soThuHai: Int)Int
scala> cong2So(2,3)
res4: Int = 5
Scala cho phép bạn gọi function với các input với tên được định nghĩa trước đó,ta thử gọi lại function trên với thứ tự input đảo ngược:
scala> cong2So(soThuHai = 3,soThuNhat = 2)
res5: Int = 5 

Vararg Parameters

Đôi khi bạn định nghĩa 1 function với với input cùng kiểu và không biết rõ số lượng , Scala đồng ý bạn viết như sau :
scala> def tinhTongNhieuSo(cacSo: Int*): Int = {
        | var tong = 0
        | for (i <- cacSo) tong += i
        | tong
        | }
tinhTongNhieuSo: (cacSo: Int*)Int
scala> tinhTongNhieuSo(1,2,3)
res6: Int = 6
scala> tinhTongNhieuSo(5,10,15,20)
res7: Int = 50

Parameter Groups

Ngoài ra ta có 1 cách define biến khác trong scala, đó là tách thành nhiều group parameter
scala> def soNaoLon(soThuNhat: Int)(soThuHai: Int) = if(soThuNhat > soThuHai) soThuNhat else soThuHai
soNaoLon: (soThuNhat: Int)(soThuHai: Int)Int
scala> soNaoLon(3)(1)
res8: Int = 3
scala> soNaoLon(3)(5)
res9: Int = 5

Function Invocation with Expression Blocks

Theo cách thông thường ,bạn sẽ chuẩn bị trc input và sau đó gọi function .
Ví dụ ở đây tôi viết hàm kiểm tra 1 số là chẵn hay lẻ :
scala> def chanHayLe(x : Int) {
         |    if (x % 2 == 0) println("so chan")
         |    else println("so le")
         | }
chanHayLe: (x: Int)Unit
Giờ tôi sẽ cộng 2 số bất kì và kiểm tra xem  số đó là chẵn hay lẻ:
scala> val tong2SoBatKy = 5 + 9
tong2SoBatKy: Int = 14
scala> chanHayLe(tong2SoBatKy)
so chan
Với Scala mọi thứ đơn giản hơn 1 bước :
scala> chanHayLe { 5 + 9}
so chan
Ví dụ này đơn giản quá so với sự hữu ích của tính năng này,trước mắt tôi chỉ muốn giới thiêu cho bạn như vậy.

Function’s Type Parameters

Đôi khi bạn cần viết 1 function mà kiểu trả về là động , ví dụ bạn viết 1 function mà kiểu trả về tưởng ứng với kiểu input.
Cách 1 :  bạn sử dụng Any vì Any là root của mọi data trong Scala như ta đã nói ở bài 1
scala> def anyThings(x : Any) : Any = x
anyThings: (x: Any)Any
scala> val soInt: Int = anyThings(1)
<console>:11: error: type mismatch;
 found   : Any
 required: Int
       val soInt: Int = anyThings(1)
                                 ^
Ở đây anyThings của 1 không trả về 1 số Int vì qua hàm anyThings nó đã biến thành kiểu Any
Cách 2: Scala cung cấp cho bạn 1 giải pháp cho tình huống này :
scala> def anyThings[A](x : A) : A = x
anyThings: [A](x: A)A
scala> val soInt: Int = anyThings(1)
soInt: Int = 1

Nested Functions 

Scala cho phép bạn khai báo function trong function  :
scala> def timSoLonTrong3So(soI: Int, soII: Int, soIII: Int) = {
            |    def timSoLonTrong2So(soI: Int, soII: Int) = if(soI > soII) soI else soII
            |    timSoLonTrong2So(soI,timSoLonTrong2So(soII,soIII))
            | }
timSoLonTrong3So: (soI: Int, soII: Int, soIII: Int)Int
scala> timSoLonTrong3So(5,15,10)
res1: Int = 15

Procedures

Procedures là function mà không trả về giá trị gì cả hay đúng hơn nó trả về 1 Unit
scala> def procedure(ten: String) = println("chao "+ ten)
procedure: (ten: String)Unit
scala> procedure("HoaiPT")
chao HoaiPT

II - Methods and Operators

Khi bắt đầu làm quen với Scala bạn sẽ bắt gặp 1 số "function" như làm tròn 1 số Double hay kiểm trả kết thúc 1 chuỗi :
scala> val soDouble : Double = 1.5645
soDouble: Double = 1.5645
scala> soDouble.round
res6: Long = 2
scala> val tenToi : String = "HoaiPT"
tenToi: String = HoaiPT
scala> tenToi.endsWith("PT")
res7: Boolean = true
Như chúng ta đã tìm hiểu ở bài đầu tiên,mọi data trong scala đều là 1 class ,và những function mà bạn bắt gặp kia thực chất là method của class đó.
Mỗi loại dữ liệu định nghĩa như 1 class và có những method đi kèm tương ứng.
Có rất nhiều method cho mỗi class data type và bài tập của các bạn hãy tìm hiểu thật nhiều những method đó trước khi ta đến với bài tiếp theo về  First-Class Functions

Comments

  1. Parameter Groups cái này là currying chứ bạn nhỉ

    ReplyDelete
    Replies
    1. vâng,nhưng mình muốn diễn giai nó theo hướng này vì cảm thấy đơn giản hiểu thế là đủ

      Delete

Post a Comment