Data Class

ممکن است تحت شرایطی نیاز داشته باشید تا کلاسی ایجاد کنید که فقط برای نگهداری از داده‌ها مورد استفاده قرار گیرد. در چنین مواردی، شما می‌توانید با استفاده از کلمه کلیدی data، یک data class یا کلاس داده‌ای ایجاد کنید. به مثال زیر توجه کنید:

data class Person(val name: String, var age: Int)

کامپایلر به صورت خودکار توابع زیر را برای همه Property هایی که در سازنده این کلاس تعریف شده‌اند ایجاد می‌کند:

  • جفت تابع ()eaqul و ()hashcode
  • تابع ()toString که خروجی آن به شکل Person(name=jack, age=30) است
  • توابع ()componentN
  • تابع ()copy

قبل از آنکه در مورد جزئیات این توابع صحبت کنیم، می‌خواهیم نیازمندی‌هایی که یک data class دارد را مورد بررسی قرار دهیم:

به مثال زیر توجه کنید:

data class Person(val name: String, val age: Int)

fun main(args: Array<String>)
{
    val jack = Person("jack", 29)
    println("name = ${jack.name}")
    println("age  = ${jack.age}")
}
name = jack
age = 29

وقتی شما یک data class ایجاد می‌کنید، کامپایلر به صورت خودکار توابعی مانند ()toString()، equals() ،hashcode و… را در پشت صحنه تولید می‌کند و این باعث می‌شود تا کدهایی که می‌نویسیم خلاصه‌تر باشند. در صورتی که در جاوا، همیشه تعداد زیادی از کدها Boilerplate هستند. Boilerplate به بلوکی از کدها گفته می‌شوند که همیشه مجبوریم آن‌ها را بنویسیم و همین موضوع باعث می‌شود حجم کدهای ما زیادتر شود. حال می‌خواهیم توابعی که پیش‌تر گفته شد را با جزئیات بیشتر بررسی کنیم. با استفاده از تابع ()copy می‌توانیم یک شیء از یک data class را با Property های دلخواه کپی کنیم. به مثال زیر توجه کنید:

data class Person(val name: String, val age: Int)

fun main(args: Array<String>)
{
    val person1 = Person("John", 29)

    // using copy function to create an object
    val person2 = person1.copy(name = "Randy")

    println("person1: name = ${person1.name}, name = ${person1.age}")
    println("person2: name = ${person2.name}, name = ${person2.age}")
}
person1: name = John, name = 29
person2: name = Randy, name = 29

در این مثال ابتدا یک نمونه از Person به نام person1 ایجاد کردیم و مقادیر John و 29 را برای آن در نظر گرفتیم. سپس در خط بعد، یک متغیر به نام person2 ایجاد کردیم و با استفاده از تابع ()copy، تمام مقادیر person1 را در person2 کپی کردیم اما با این تفاوت که مقدار name را برابر با Randy قرار دادیم. با استفاده از تابع ()toString می‌توانیم یک شیء را به همراه مقادیری که Property های آن دارند به صورت یک string نمایش دهیم.

data class Person(val name: String, val age: Int)

fun main(args: Array<String>)
{
    val person1 = Person("John", 29)
    println(person1.toString())
}
Person(name=John, age=29)

تابع ()hashCode مقدار هش یک شیء را بر می‌گرداند. اگر دو شیء با یکدیگر برابر باشند، مقدار هش آن‌ها نیز یکسان است. تابع ()equals اگر دو شیء با یکدیگر یکسان باشند، مقدار true و در غیر اینصورت مقدار false را بر می‌گرداند. برای اینکه برابری دو شیء را تشخیص دهد از ()hashCode استفاده می‌کند.

data class Person(val name: String, val age: Int)

fun main(args: Array<String>)
{
    val person1 = Person("John", 29)
    val person2 = person1.copy()
    val person3 = person1.copy(name = "Amanda")

    println("person1 hashcode = ${person1.hashCode()}")
    println("person2 hashcode = ${person2.hashCode()}")
    println("person3 hashcode = ${person3.hashCode()}")

    if (person1.equals(person2))
        println("person1 is equal to person2.")
    else
        println("person1 is not equal to person2.")

    if (person1.equals(person3))
        println("person1 is equal to person3.")
    else
        println("person1 is not equal to person3.")
}
person1 hashcode = 71750738
person2 hashcode = 71750738
person3 hashcode = 771732263
person1 is equal to person2.
person1 is not equal to person3.

Destructuring در تعریف متغیرها

ابتدا به مثال زیر توجه کنید:

data class Person(val name: String, val age: Int, val gender: String)

fun main(args: Array<String>)
{
    val person1 = Person("John", 29, "Male")

    val (name, age, gender) = person1
    println("name   = $name")
    println("age    = $age")
    println("gender = $gender")
}

در اینجا ابتدا یک data class به نام Person تعریف کرده و سپس یک نمونه به نام person1 از آن ایجاد کردیم. در خط بعد با استفاده از ساختار زیر که به آن Destructuring Declaration گفته می‌شود، سه متغیر name، age و gender را مقدار دهی کردیم:
val (name, age, gender) = person1
حال زمانی که برنامه بالا را اجرا کنیم خروجی زیر را مشاهده خواهید کرد:

name   = John
age      = 29
gender = Male

ساختار فوق در پشت صحنه به شکل زیر تفسیر می‌شود:

val name   = person1.component1()
val age    = person1.component2()
val gender = person1.component3()

به عبارت دیگر توابع component1()، component2() و component3() به ترتیب مقادیر John، 29 و Male را در متغیرهای مشخص شده قرار می‌دهند.