กลไก expect/actual สำหรับ API ของแพลตฟอร์ม
ประกาศสิ่งที่คาดว่าจะมีในโค้ดส่วนกลางและจัดเตรียมการใช้งานจริงแยกตามแพลตฟอร์ม
กลไก expect/actual สำหรับ API ของแพลตฟอร์ม เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
รูปแบบ expect/actual
expect ประกาศสัญญา API ใน commonMain แต่ละแพลตฟอร์มจะจัดเตรียมการใช้งาน actual คอมไพเลอร์จะตรวจสอบว่าทุกเป้าหมายมี actual
// commonMain:
expect fun platformName(): String
// androidMain:
actual fun platformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"
// iosMain:
actual fun platformName(): String = UIDevice.currentDevice.systemName()expect class
expect class ประกาศคลาสพร้อม API ของคลาสนั้นใน commonMain แต่ละแพลตฟอร์มจะจัดเตรียมการใช้งานครบถ้วน
// commonMain:
expect class DateTime {
fun format(pattern: String): String
val timestamp: Long
}
// androidMain:
actual class DateTime {
actual val timestamp = System.currentTimeMillis()
actual fun format(pattern: String): String =
java.text.SimpleDateFormat(pattern).format(java.util.Date(timestamp))
}expect object
expect object ประกาศซิงเกิลตันพร้อมสัญญาของมัน เหมาะสำหรับยูทิลิตีเฉพาะแพลตฟอร์ม เช่น การบันทึกข้อมูล การตั้งค่า หรือการวิเคราะห์
// commonMain:
expect object Logger {
fun debug(msg: String)
fun error(msg: String, cause: Throwable? = null)
}
// androidMain:
actual object Logger {
actual fun debug(msg: String) = android.util.Log.d("App", msg)
actual fun error(msg: String, cause: Throwable?) =
android.util.Log.e("App", msg, cause)
}expect val / fun ระดับบนสุด
expect val และ expect fun ระดับบนสุดเรียบง่าย และเหมาะกับยูทิลิตีแพลตฟอร์มที่ไม่มีสถานะ
// commonMain:
expect val isDebugBuild: Boolean
expect fun generateUUID(): String
// androidMain:
actual val isDebugBuild: Boolean = BuildConfig.DEBUG
actual fun generateUUID(): String = java.util.UUID.randomUUID().toString()
// iosMain:
actual val isDebugBuild: Boolean = false // or a native flag
actual fun generateUUID(): String = NSUUID().UUIDString()expect fun พร้อมการใช้งานเริ่มต้น
ตั้งแต่ Kotlin 1.9 เป็นต้นไป expect fun สามารถมีการใช้งานเริ่มต้นผ่าน expect fun f() { } ได้ แพลตฟอร์มต่าง ๆ จะเขียนทับหรือใช้การใช้งานเริ่มต้นนี้ก็ได้
// commonMain (Kotlin 1.9+):
expect fun log(msg: String) {
println("[DEFAULT] $msg") // used if no actual overrides
}
// androidMain:
actual fun log(msg: String) = android.util.Log.d("KMP", msg)
// iosMain (uses default):
// no actual needed — default is usedActual Typealias
หากแพลตฟอร์มมีคลาสที่ตรงกับความต้องการอยู่แล้ว ให้ใช้ actual typealias เพื่อชี้ไปยังคลาสนั้นแทนการสร้างคลาสห่อหุ้ม
// commonMain:
expect class AtomicInt {
fun get(): Int
fun incrementAndGet(): Int
}
// androidMain / jvmMain:
actual typealias AtomicInt = java.util.concurrent.atomic.AtomicInteger
// iosMain:
actual class AtomicInt {
private var value = 0
actual fun get() = value
actual fun incrementAndGet() = ++value
}expect interface (รูปแบบทางอ้อม)
หากต้องการความยืดหยุ่นมากขึ้น ให้ประกาศอินเทอร์เฟซใน commonMain และใช้ expect/actual เฉพาะกับโรงงานที่สร้างอินสแตนซ์ของแพลตฟอร์ม
// commonMain:
interface FileStorage {
suspend fun readFile(path: String): ByteArray
suspend fun writeFile(path: String, data: ByteArray)
}
expect fun createFileStorage(): FileStorage
// androidMain:
actual fun createFileStorage(): FileStorage = AndroidFileStorage()
// iosMain:
actual fun createFileStorage(): FileStorage = IosFileStorage()การทดสอบด้วย expect/actual
ใน commonTest ให้ทดสอบ API ที่ใช้ร่วมกัน การใช้งาน actual จะทำงานระหว่างงานทดสอบเฉพาะแพลตฟอร์ม (testDebugUnitTest บน Android และ iosX64Test บน iOS)
// commonTest:
import kotlin.test.Test
import kotlin.test.assertNotNull
class PlatformTest {
@Test
fun testUUID() {
val uuid = generateUUID()
assertNotNull(uuid)
println("UUID: $uuid")
}
}ข้อผิดพลาดที่พบบ่อย
การประกาศ expect ทุกตัวต้องมี actual ใน ALL เป้าหมายที่กำหนดค่าไว้ มิฉะนั้นการสร้างโปรเจกต์จะล้มเหลว ระบบจะตรวจพบ actual ที่ขาดหายไปขณะคอมไพล์
// If you add a new target (e.g., jvmMain), you must add:
// actual fun platformName(): String = "JVM"
// Otherwise:
// error: Expected function platformName has no actual declaration in module :shared for JVM
fun main() { println("Missing actuals = compile error") }คลาสคำอธิบายประกอบ expect
expect annotation class ช่วยให้แมปคำอธิบายประกอบเฉพาะแพลตฟอร์มได้ เช่น การแมปคำอธิบายประกอบที่ใช้ร่วมกันซึ่งคล้ายกับ @Parcelize ไปยังปลั๊กอิน Parcelize ของ Android
// commonMain:
expect annotation class CommonParcelize()
// androidMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelize
// iosMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelizeกรณีใช้งานจริง: Keychain/Preferences
ตัวอย่าง expect/actual ในโลกจริงคืออินเทอร์เฟซพื้นที่จัดเก็บข้อมูลปลอดภัย โดย Android ใช้ EncryptedSharedPreferences และ iOS ใช้ Keychain
// commonMain:
expect class SecureStorage {
fun save(key: String, value: String)
fun get(key: String): String?
}
// androidMain:
actual class SecureStorage {
private val prefs = /* EncryptedSharedPreferences */ mapOf<String,String>()
actual fun save(key: String, value: String) { /* ... */ }
actual fun get(key: String): String? = null // simplified
}ตรวจสอบความเข้าใจ
หากการประกาศ expect ไม่มี actual สำหรับเป้าหมายหนึ่ง จะเกิดอะไรขึ้นขณะคอมไพล์
สรุปทบทวน
expect ประกาศ API ใน commonMain ส่วน actual จัดเตรียมการใช้งานบนแพลตฟอร์ม ใช้ actual typealias เมื่อแพลตฟอร์มมีชนิดข้อมูลที่ต้องการอยู่แล้ว ระบบจะตรวจพบ actual ที่ขาดหายไปขณะคอมไพล์ จึงไม่มีปัญหาที่คาดไม่ถึงขณะรันไทม์
คำถามที่พบบ่อย
บทเรียน “กลไก expect/actual สำหรับ API ของแพลตฟอร์ม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กลไก expect/actual สำหรับ API ของแพลตฟอร์ม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กลไก expect/actual สำหรับ API ของแพลตฟอร์ม”
ประกาศสิ่งที่คาดว่าจะมีในโค้ดส่วนกลางและจัดเตรียมการใช้งานจริงแยกตามแพลตฟอร์ม คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “กลไก expect/actual สำหรับ API ของแพลตฟอร์ม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- โครงสร้างโปรเจกต์ KMP: commonMain, androidMain, iosMain
- กลไก expect/actual สำหรับ API ของแพลตฟอร์ม
- การแชร์ชั้น Repository และ Use Case
- การฉีดการพึ่งพาใน KMP ด้วย Koin