Для чего нужна данная статья? :
- Изучить интеграцию Kotlin Multiplatform с Rust через FFI.
- Написать код для работы с ML.
Зачем Вам это уметь? :
Научиться работать с разными моделями памяти Rust и Kotlin, и научиться передавать данные pytorch между Rust и Kotlin.
Код создает список дел с использованием ML:
- namespace — папка для кода.
- TodoList — интерфейс списка дел.
- TodoEntry — одна задача в списке.
- TodoError — возможные ошибки.
- Пишется на Kotlin и Rust.
- Работает на Android, iOS, десктопе и других платформах.
- Использует Uniffi для связи между Rust и Kotlin.
- Собирается с помощью Gradle специальных плагинов и команды, например cargo build --target aarch64-linux-android.
namespace todolist { ... }
Что это?
Это как папка или контейнер для всех функций, классов и типов, связанных с TodoList. Все имена внутри namespace todolist не будут конфликтовать с такими же именами в других частях программы.
Пример:
Представьте, что у вас есть две папки: "Работа" и "Дом". В каждой может быть файл "Список дел". Так и здесь: все функции и типы внутри todolist относятся только к этому списку дел.
TodoList? get_default_list();
Что это?
Функция, которая возвращает стандартный список дел (TodoList). Знак ? означает, что она может вернуть либо список, либо null (то есть ничего).
Пример:
Как если бы вы спросили: "Дай мне мой основной список покупок", а вам ответили: "Вот он" или "У тебя нет основного списка".
undefined set_default_list(TodoList list);
Что это?
Функция, которая устанавливает новый стандартный список дел. undefined означает, что функция ничего не возвращает (просто выполняет действие).
Пример:
Как если бы вы сказали: "Сделай этот список моим основным".
[Throws=TodoError]
Что это?
Это значит, что функция может "выбросить" ошибку типа TodoError. То есть, если что-то пойдёт не так, программа может остановиться и сказать, что именно пошло не так.
Пример:
Если вы пытаетесь добавить пустую строку в список, функция может сказать: "Ошибка: EmptyString".
dictionary TodoEntry { string text; }
Что это?
Определение типа TodoEntry — это как запись в списке дел. У неё есть одно поле: text (строка).
Пример:
{ text: "Купить молоко" }
enum TodoError { ... }
Что это?
Список возможных ошибок, которые могут произойти при работе со списком дел.
Примеры ошибок:
- TodoDoesNotExist — такой задачи нет.
- EmptyTodoList — список пуст.
- DuplicateTodo — такая задача уже есть.
- EmptyString — нельзя добавить пустую строку.
- DeligatedError — ошибка от другой функции.
interface TodoList { ... }
Что это?
Описание того, что должен уметь делать любой список дел (TodoList). Это как договор: если класс реализует этот интерфейс, он обязан иметь все эти функции.
Примеры функций:
- add_item(string todo) — добавить задачу (например, "Купить хлеб").
- get_entries() — получить все задачи в виде списка.
- get_last_sentiment() — получить "настроение" последней задачи (например, 0.8 — позитивное).
[Self=ByArc] и undefined make_default();
Что это?
- [Self=ByArc] — техническая деталь, означает, что объект будет передан "по ссылке" (эффективно, без копирования).
- make_default() — функция, которая делает текущий список стандартным.
Пример:
Как если бы вы сказали: "Сделай этот список моим основным".
Импорты (import)
Что это?
Это подключение готовых библиотек или модулей, чтобы использовать их функции в вашем проекте.
Пример:
import gobley.gradle.GobleyHost
Здесь подключается модуль GobleyHost, чтобы потом можно было проверить, на какой платформе (например, MacOS) запущен проект.
Плагины (plugins)
Что это?
Плагины добавляют новые возможности в процесс сборки проекта.
Пример:
kotlin("multiplatform")
id("dev.gobley.cargo")
- kotlin("multiplatform") — позволяет писать код, который будет работать на разных платформах (Android, iOS, десктоп).
- dev.gobley.cargo — плагин для работы с Rust-кодом (например, для сборки библиотек на Rust).
Cargo (Rust)
Что это?
Это блок для настройки сборки Rust-кода. Здесь указывается, как и для каких платформ собирать Rust-библиотеки.
Пример:
cargo {
builds.appleMobile {
variants {
if (rustTarget.tier(project.rustVersion.get()) >= 3) {
buildTaskProvider.configure {
nightly = true
extraArguments.add("-Zbuild-std")
}
}
}
}
}
- builds.appleMobile — сборка для мобильных устройств Apple.
- nightly = true — использование ночной (экспериментальной) версии компилятора Rust.
- extraArguments.add("-Zbuild-std") — дополнительные флаги для компилятора.
Uniffi
Что это?
Инструмент для генерации связок (bindings) между Rust и Kotlin, чтобы можно было вызывать Rust-код из Kotlin.
Пример:
uniffi {
bindgenFromPath(rootProject.layout.projectDirectory.dir("crates/gobley-uniffi-bindgen"))
generateFromUdl {
udlFile = layout.projectDirectory.file("src/todolist.udl")
namespace = "todolist"
}
}
- bindgenFromPath — путь к инструменту, который генерирует связки.
- udlFile — файл с описанием интерфейсов (что и как будет доступно из Kotlin).
- namespace — пространство имён для сгенерированного кода.
Kotlin Multiplatform
Что это?
Настройка целевых платформ, для которых будет собираться Kotlin-код.
Пример:
kotlin {
androidTarget { ... }
jvm("desktop")
iosArm64()
macosArm64()
...
}
- androidTarget — сборка под Android.
- jvm("desktop") — сборка под десктоп (Java-машина).
- iosArm64() — сборка под iPhone.
Android
Что это?
Настройка специфичных для Android параметров сборки.
Пример:
android {
namespace = "dev.gobley.uniffi.examples.todolist"
compileSdk = libs.versions.android.compileSdk.get().toInt()
...
}
- namespace — уникальный идентификатор вашего приложения.
- compileSdk — версия Android SDK, под которую компилируется проект.
Java Toolchain
Что это?
Указание версии Java, которая будет использоваться для сборки.
Пример:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
- languageVersion = JavaLanguageVersion.of(17) — проект будет собираться с использованием Java 17.
SentimentModel — анализ тональности текста
Что это?
Это модель машинного обучения, которая анализирует текст и определяет, положительный он, отрицательный или нейтральный.
Пример:
fn get_last_sentiment(&self) -> Result<f64> {
let last = self.get_last()?;
let inputs = [last.as_str()];
let sentiments: Vec<Sentiment> = SENTIMENT_MODEL.predict(&inputs);
// ...
}
Здесь функция берёт последний элемент из списка дел и анализирует его тональность.
uniffi::include_scaffolding! — связь с другими языками
Что это?
Это макрос, который позволяет использовать Rust-код из других языков программирования (например, Kotlin или Swift).
Работа с памятью (destroy, use)
Что это?
В этом коде используется Rust-библиотека, поэтому важно правильно освобождать память, чтобы не было "утечек". Для этого есть методы destroy и блок use.
Пример:
TodoList().use { todo2 ->
// Здесь todo2 будет автоматически уничтожен после блока
}
→ После выполнения кода в блоке todo2 будет удалён, память освобождена.
Анализ настроения (sentiment analysis)
Что это?
В коде есть функция, которая оценивает "настроение" текста задачи (положительное, отрицательное, нейтральное) и возвращает число от -1 до 1.
Примеры:
todo.addItem("Отличная задача! :)")
todo.getLastSentiment() shouldBeGreaterThan 0.5 // Положительное настроение
todo.addItem("Ужасная задержка :(")
todo.getLastSentiment() shouldBeLessThan -0.5 // Отрицательное настроение
Работа с дефолтным списком (default list)
Что это?
Можно сделать один из списков "дефолтным" (основным), и с ним будут работать другие части программы.
Пример:
setDefaultList(todo) // Устанавливаем todo как дефолтный список
getDefaultList() // Получаем дефолтный список