Какие знаешь особенности expect/actual?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Особенности expect/actual в Kotlin Multiplatform
expect/actual — это ключевой механизм Kotlin Multiplatform (KMP) для реализации платформно-специфичного кода, сохраняя общий интерфейс. Он позволяет декларировать ожидаемое поведение в общем модуле (expect) и предоставлять конкретные реализации для каждой целевой платформы (actual).
Основные принципы и синтаксис
Expect декларация располагается в общем модуле (commonMain) и определяет контракт без реализации:
// В модуле commonMain
expect class PlatformLogger {
fun log(message: String)
}
expect fun getCurrentTime(): Long
Actual реализация предоставляется в платформных модулях (androidMain, iosMain, etc.):
// В модуле androidMain
actual class PlatformLogger {
actual fun log(message: String) {
Log.d("App", message) // Используем Android-specific API
}
}
actual fun getCurrentTime(): Long {
return System.currentTimeMillis() // Android реализация
}
Ключевые особенности и правила
-
Строгая симметрия: Каждой
expectдекларации должна соответствовать однаactualреализация для каждой целевой платформы. Имена, модификаторы и сигнатуры должны полностью совпадать. -
Платформная изоляция:
expectчасть не может содержать реализацию — только объявление. Это гарантирует, что общий модуль остается чистым от платформного кода. -
Область применения: Можно использовать для:
- Классы (обычные, интерфейсы, объекты)
- Функции (включая top-level и членов классов)
- Свойства (с возможностью указания custom getter/setter в actual)
- Аннотации
-
Модификаторы видимости:
actualреализации могут расширять видимость, но не сокращать. Например,expect internalкласс может быть реализован какactual publicна конкретной платформе. -
Инициализация actual классов: Для
expect classможно указать конструкторы в expect части, но их реализация будет в actual.
// commonMain
expect class FileHandler(path: String) {
fun read(): String
}
// androidMain
actual class FileHandler actual constructor(actual val path: String) {
actual fun read(): String {
return File(path).readText()
}
}
Практические примеры использования в Android контексте
1. Работа с системными API
// commonMain
expect fun shareText(text: String)
// androidMain
actual fun shareText(text: String) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, text)
startActivity(Intent.createChooser(intent, null))
}
2. Платформные утилиты
// commonMain
expect object PlatformUtils {
val isNetworkAvailable: Boolean
}
// androidMain
actual object PlatformUtils {
actual val isNetworkAvailable: Boolean
get() {
val connManager = getSystemService<ConnectivityManager>()
return connManager.activeNetworkInfo?.isConnected ?: false
}
}
Преимущества и ограничения
Преимущества:
- Чистая архитектура: Общий код полностью абстрагирован от платформных деталей.
- Безопасность: Компилятор проверяет соответствие expect/actual, предотвращая ошибки.
- Поддержка инструментов: IDE (IntelliJ IDEA) предоставляет удобную навигацию между expect и actual.
Ограничения и нюансы:
- Не для всех случаев: Для простых случаев часто используют expected/actual, но для сложных многоплатформных структур иногда применяют интерфейсы с платформными внедрениями через DI.
- Ограниченная рефлексия:
actualтипы могут иметь ограничения в платформно-специфичной рефлексии. - Тестирование: Тесты для common модуля могут использовать только
expectчасти, что требует особых подходов к тестированию мультиплатформного кода.
Best Practices для Android разработчиков
- Минимизация expect деклараций: Использовать только для действительно необходимого платформного кода. Стараться максимально выносить логику в common модуль.
- Единые контракты: Определять четкие интерфейсы в expect, не допуская их изменения на разных платформах.
- Логирование архитектуры: При сложных мультиплатформных проектах создавать маппинг между expect и actual для документации.
// Пример документации в коде
/**
* expect: Общий контракт для получения устройства
* actual Android: Использует Build.MODEL + другие Android API
* actual iOS: Использует UIDevice.current.model
*/
expect fun getDeviceModel(): String
expect/actual — это фундаментальный инструмент Kotlin Multiplatform, который позволяет Android разработчикам создавать кроссплатформные решения, сохраняя возможность использовать всю мощь Android-specific API в соответствующих реализациях. Правильное использование этого механизма — ключ к созданию maintainable и scalable мультиплатформных проектов.