วันเสาร์ที่ 16 พฤษภาคม พ.ศ. 2558

Using Implicit class in Scala

วันนี้เรามาดูเรื่อง implicit class กันครับ บางครั้งเราต้องการที่จะเพิ่มเมทธอดให้กับ class ของคนอื่นที่เรานำมาใช้ (reference library) เราอาจทำได้โดย inherit แล้วเพิ่มเมทธอดเข้าไป ถ้า class นั้นๆ ไม่ได้เป็น final class ใน java หรือ sealed class ใน c#  อีกวิธีหนึ่งเราอาจจะสร้าง wrapper class มาใช้งานแทน ตัวอย่างเช่น เราต้องการเพิ่มเมทธอด paddingLeftให้กับ string เราอาจะสร้าง wrapper class ได้ดังนี้

class MyWrapperString {
  private String str;
  public MyWrapperString(String str) {
    this.str = str;
  }
  public String paddingLeft(int n) {
     String ret = "";
     for(int i = 0; i < n; i++)
     {
       ret += " ";
     }
     return ret + str;
  }
}

จะเห็นได้ว่าคนที่เอา class นี้ไปใช้ไม่ได้รู้สึกว่าใช้ String ที่คุ้นเคย ถึงแม้ว่ามี paddingLeft ให้ใช้ก้อตามที ดูตัวอย่างข้างล่างนี้

MyWrapperString str = new MyWrapperString("Hello");
String output = str.paddingLeft(10);

ในที่นี้ output จะมี 10 space ก่อนหน้าคำว่า  Hello

ใน Scala เราใช้ implicit class เพื่อที่จะทำหน้าที่อย่างนี้ครับ ที่สำคัญคือ เราไม่จำเป็นต้อง inherit หรือว่า สร้าง  wrapper ขึ้นมาเลย




เราสร้าง implicit class MyString ภายใน object Hello แล้วประกาศเมทธอด paddingLeft เหมือนที่เราทำมาก่อนหน้านี้ ทีนี้มาดูวิธีเอาไปใช้กัน


ก่อนอื่นเราจะต้อง import เมทธอดทั้งหมดของ object Helper มาใช้ โดยการ

import Helper._

หรือถ้าเราต้องการ ระบุ class ไปเลยก้อระบุได้ตามนี้


import Helper.MyString

หลังจาก import มาใช้งานแล้ว ตัวแปรที่ชนิด string ทั้งหมดจะสามารถใช้เมทธอด  paddingLeft ได้โดยอัตโนมัติ ผู้ที่เรียกใช้ยังคงประกาศตัวแปรเป็น string และใช้ data/method ต่างๆ ของ string ได้โดยปรกติ แถมยังใช้ paddingLeft ได้อีกด้วย

ที่เป็นเช่นนี้เพราะเราประกาศ  implicit class MyString(str : String) นั่นเอง อย่างไรก้อตามเรามีข้อจำกัดในการประกาศใช้ implicit class ดังต่อไปนี้

1. implicit class ไม่สามารถเป็น top level class ได้ ต้องอยู่ภายใน object หรือ class หรือ trait อื่นๆ ในตัวอย่างที่เราดูกันก้ออยู่ภายใน object Helper

2. implicit class มี parameter ใน primary constructor ได้เพียงตัวเดียว เราไม่สามารถทำอย่างนี้ได้

implicit class MyString(str:String, n:Int)

3. ผู้ที่นำไปใช้ต้อง import object หรือ class หรือ trait ไปใช้งาน ในกรณีของเราคือ import Helper._

4. ห้ามตั้งชื่อ implicit class ตรงกับ top level class เราไม่สามารถใช้อย่างนี้ได้

object MyString {
   implicit class MyString(str:String)
}

สำหรับผู้ที่ใช้ c# อยู่จะเห็นได้ว่าคล้ายๆ กับ extension method นั่นเอง สำหรับบทความต่อไปเราจะมาดู implicit parameter กันครับ

ไม่มีความคิดเห็น: