Class & Struct

นอกจาก type พื้นฐานที่ Swift มีมาให้แล้ว นอกจาก Enum ที่เราสามารถสร้าง type ใหม่ได้แล้ว ยังมี Class กับ Struct อีกที่เราสามารถนำมาสร้าง type ใหม่ได้

ในบางครั้งเราต้องการเก็บข้อมูลที่เกี่ยวข้องกันหลายประเภทไว้ด้วยกัน เนื่องจาก type มาตรฐานไม่สามารถทำได้ เราจึงต้องประกาศ type ใหม่ของเราเอง

เช่น เราต้องการ type ใหม่เพื่อเก็บข้อมูล user หนึ่งคน ซึ่งอาจประกอบไปด้วย ชื่อ นามสกุล อายุ ส่วนสูง และอื่น ๆ ถ้าเราใช้ type มาตรฐาน จะกลายเป็นว่าเราจะต้องมีตัวแปรมากมาย ซึ่งจะทำให้โค้ดของเราจัดการ, แก้ไข หรืออ่านได้เข้าใจยาก

การประกาศ Struct และ Class

struct Position {
    // structure definition goes here
}
class Person {
    // class definition goes here
}

ทั้ง Struct และ Class เราสามารถมี store properties ในการเก็บค่าได้แบบนี้

struct Position {
    var x = 0
    var y = 0
}

class Person {
    var name = ""
    var age = 20
}

ในการสร้าง instance ของ Struct และ Class เราสามารถทำได้แบบนี้

let origin = Position()
let pop = Person()

การอ้างถึง properties จะใช้ . ในการอ้าง

print(origin.x)
print(pop.name)

Struct จะมี initializer มาให้โดยมี argument เท่ากับ properties ที่มีเรียงตามลำดับที่ประกาศ ในกรณีที่ต้องการ initial ด้วยค่าอื่นเราสามารถทำได้เลย แบบนี้

let firstPoint = Position(x: 0, y: 5)

ทำให้เราไม่จำเป็นต้องกำหนดค่า default ตอนประกาศ Struct ได้

struct Position {
    var x: Int
    var y: Int
}

ซึ่ง Class ไม่สามารถทำได้เนื่องจากไม่มี initializer ให้ ถ้าเราเขียนแบบนี้จะ error

class Person {
    var name: String
    var age: Int
}

let john = Person(name: "John", age: 20)

เราจึงต้องเขียน initializer เองแบบนี้

class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

การอ้างอึงถึง instance ของตัวเองเราจะใช้ keyword self แต่เราจะใช้ในกรณีที่ต้องใช้ จากตัวอย่างก่อนหน้า initializer มี parameter name ที่ซำ้กันกับ property name ใน class เราจึงจำเป็นใช้ self.name ในการอ้างถึงตัวแปร name ใน class

ในกรณีที่ไม่จำเป็น เราจะไม่ใส่ self.

ทั้ง Struct และ Class สามารถมี method (ฟังก์ชั่น) ได้ทั้งคู่

struct Position {
    var x: Int
    var y: Int

    func display() {
        print("x: \(x), y: \(y)")
    }
}

class Person {
    var name: String
    var age: Int

    func display() {
        print("name: \(name) age: \(age)")
    }

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

firstPoint.display()
john.display()

Struct เป็น Value Type นั่นคือเป็นการ copy ค่าเวลามีการเปลี่ยนแปลง ไม่ได้เปลี่ยนแปลงบนตัวเองอย่าง Class ที่เป็น Reference Type ที่เมื่อ class เปลี่ยนค่าในตัวเองยังคงใช้ reference เดิมอยู่

ทำให้ Struct เวลามีการแก้ไขค่าภายหลัง การประกาศตัวแปรจะต้องใช้ var แทน let

var firstPoint = Position(x: 0, y: 5)
let john = Person(name: "John")

firstPoint.x = 6
print(firstPoint)

john.name = "john"
print(john.name)

และหากมี method ทำให้เกิดการเปลี่ยนแปลงค่าใน Struct จะต้องใส่ mutating ที่หน้าฟังก์ชั่นนั้น

struct Position {
    var x: Int
    var y: Int

    func display() {
        print(description)
    }

    mutating func move(to position: Position) {
        self.x = position.x
        self.y = position.y
    }
}

firstPoint.move(to: origin)

ทั้ง Struct และ Class สามารถมี compute properties ได้

struct Position {
    var x: Int
    var y: Int

    var description: String {
        return "x: \(x), y: \(y)"
    }

    func display() {
        print(description)
    }
    
    mutating func move(to position: Position) {
        self.x = position.x
        self.y = position.y
    }
}

class Person {
    var name: String
    var age: Int

    var description: String {
        return "name: \(name), age: \(age)"
    }

    func display() {
        print("name: \(name) age: \(age)")
    }

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

นอกจาก Struct กับ Class จะต่างกันที่ value กับ refence type แล้ว ยังมีความแตกต่างอย่างอื่นอีก ที่มีเฉพาะใน Class ดังนี้

  • ความสามารถในการ inherit จาก parent

  • การใช้ deinit ในการ deinitialize

  • การมีมากกว่า 1 reference ชี้มาที่ instance

  • type casting เป็น parent หรือ subclass (แน่นอน เพราะว่า Struct ไม่สามารถ inherit ได้แบบ class)

Last updated