- Числовые:
Byte
,Short
,Int
,Long
,Float
,Double
- Символьные:
Char
- Логические:
Boolean
- Строки:
String
val intValue: Int = 10
val longValue = 10L
val floatValue = 10.0f
val doubleValue = 10.0
val charValue = 'A'
val boolValue = true
val stringValue = "Hello, Kotlin!"
val
- неизменяемая переменная (константа)var
- изменяемая переменная
val immutable = 100 // нельзя изменить
var mutable = 200 // можно изменить
mutable = 300 // OK
- Типы по умолчанию не могут содержать
null
- Для разрешения
null
используется оператор?
var nonNullable: String = "value" // не может быть null
var nullable: String? = null // может быть null
// Безопасный вызов
val length = nullable?.length // null если nullable == null
// Элвис-оператор
val lengthOrDefault = nullable?.length ?: 0
// Оператор !!
val forceLength = nullable!!.length // NullPointerException если nullable == null
package com.example.myapp
import kotlin.math.* // импорт всех функций из пакета
import com.example.utils.Helper // импорт конкретного класса
import com.example.utils.Helper as UtilHelper // импорт с переименованием
public
(по умолчанию) - доступно вездеprivate
- доступно только внутри файла/классаprotected
- как private, но доступно в подклассахinternal
- доступно внутри модуля
internal class InternalClass
private fun privateFunction() = "Only visible in this file"
+
,-
,*
,/
,%
==
,!=
,>
,<
,>=
,<=
===
,!==
(сравнение по ссылке)
&&
,||
,!
shl
,shr
,ushr
,and
,or
,xor
,inv
val a = 10
val b = 3
val result = a and b // побитовое И
as
- небезопасное приведениеas?
- безопасное приведениеis
- проверка типа
val obj: Any = "String"
if (obj is String) {
// Smart cast - внутри этого блока obj автоматически приводится к String
println(obj.length)
}
val safeString = obj as? String // null, если obj не String
val unsafeString = obj as String // ClassCastException, если obj не String
data class Vector(val x: Int, val y: Int) {
// Перегрузка оператора +
operator fun plus(other: Vector) = Vector(x + other.x, y + other.y)
// Перегрузка оператора *
operator fun times(scalar: Int) = Vector(x * scalar, y * scalar)
// Перегрузка оператора []
operator fun get(index: Int): Int {
return when(index) {
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException()
}
}
}
// Использование
val v1 = Vector(1, 2)
val v2 = Vector(3, 4)
val sum = v1 + v2 // Vector(4, 6)
val scaled = v1 * 3 // Vector(3, 6)
val xCoord = v1[0] // 1
// if как выражение
val max = if (a > b) a else b
// when (аналог switch)
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x is neither 1 nor 2")
}
// when без аргумента
when {
x > 0 -> print("x is positive")
x < 0 -> print("x is negative")
else -> print("x is 0")
}
// for
for (i in 1..10) { /* ... */ }
for (i in 1 until 10) { /* ... */ }
for (i in 10 downTo 1 step 2) { /* ... */ }
// while и do-while
while (condition) { /* ... */ }
do { /* ... */ } while (condition)
when (obj) {
is Int -> println("Int: $obj")
is String -> println("String: $obj")
is List<*> -> println("List with ${obj.size} elements")
else -> println("Unknown")
}
fun sum(a: Int, b: Int): Int {
return a + b
}
// Функция-выражение
fun sum(a: Int, b: Int) = a + b
// Функция без возвращаемого значения
fun printSum(a: Int, b: Int): Unit {
println("$a + $b = ${a + b}")
}
fun greet(name: String = "Guest") = println("Hello, $name!")
fun createUser(name: String, age: Int, isAdmin: Boolean) { /* ... */ }
createUser(name = "Alice", age = 30, isAdmin = false)
fun printAll(vararg messages: String) {
for (m in messages) println(m)
}
printAll("Hello", "World", "!")
Позволяют вызывать функции в инфиксной нотации (без точки и скобок)
infix fun Int.plus(other: Int) = this + other
val result = 1 plus 2 // вместо 1.plus(2)
Позволяют добавлять функциональность к существующим классам
fun String.addExclamation() = "$this!"
println("Hello".addExclamation()) // "Hello!"
val sum = { a: Int, b: Int -> a + b }
val result = sum(1, 2) // 3
// С выводом типов
val numbers = listOf(1, 2, 3)
numbers.filter { it > 1 }
fun operation(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
val result = operation(1, 2) { a, b -> a + b }
// Функция, принимающая два Int и возвращающая Int
val func1: (Int, Int) -> Int = { a, b -> a + b }
// Функция, принимающая String и ничего не возвращающая (Unit)
val func2: (String) -> Unit = { println(it) }
// Функция без параметров, возвращающая String
val func3: () -> String = { "Hello" }
// Функция с nullable возвращаемым типом
val func4: (Int) -> Int? = { if (it > 0) it else null }
// Nullable функциональный тип
val func5: ((Int) -> Int)? = null
// Последний параметр - лямбда
fun processNumbers(list: List<Int>, processor: (Int) -> Int): List<Int> {
return list.map(processor)
}
// Вызов с лямбдой в скобках
val result1 = processNumbers(listOf(1, 2, 3), { it * 2 })
// Вызов с лямбдой за скобками (trailing lambda syntax)
val result2 = processNumbers(listOf(1, 2, 3)) { it * 2 }
// Тип функции с приемником String
val appendExclamation: String.() -> String = { "$this!" }
// Использование
val result = "Hello".appendExclamation() // "Hello!"
// Функция, принимающая лямбду с приемником
fun buildString(builder: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb.builder() // вызов лямбды с приемником
return sb.toString()
}
// Использование
val result = buildString {
append("Hello")
append(", ")
append("World!")
}
// Ссылка на функцию
fun isEven(n: Int) = n % 2 == 0
val numbers = listOf(1, 2, 3, 4)
val evenNumbers = numbers.filter(::isEven)
// Ссылка на метод объекта
val str = "Hello"
val isNotEmpty = str::isNotEmpty
println(isNotEmpty()) // true
// Ссылка на метод класса
val isEmptyMethod = String::isEmpty
println(isEmptyMethod("")) // true
// Ссылка на конструктор
data class Person(val name: String)
val createPerson = ::Person
val person = createPerson("Alice")
fun makeCounter(): () -> Int {
var count = 0
return { count++ } // лямбда захватывает переменную count
}
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
// Inline-функция устраняет накладные расходы на создание объекта-функции
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}
val time = measureTime {
// код, время выполнения которого нужно измерить
}
// crossinline запрещает нелокальные возвраты в лямбде
inline fun processWithCallback(crossinline callback: () -> Unit) {
runOnUiThread { callback() }
}
// noinline отключает inline для конкретного параметра
inline fun process(inlined: () -> Unit, noinline notInlined: () -> Unit) {
inlined()
runOnBackground(notInlined) // передача функции дальше
}
// Лямбда с приемником (this)
val sum = fun Int.(other: Int): Int {
return this + other
}
1.sum(2) // 3
// Лямбда с несколькими строками
val process = { x: Int ->
val y = x * 2
val z = y + 1
z
}
class Person(val firstName: String, var age: Int) {
// Первичный конструктор выше
// Вторичный конструктор
constructor(firstName: String) : this(firstName, 0)
// Метод
fun greet() = "Hello, I'm $firstName"
// Свойство
val isAdult: Boolean
get() = age >= 18
}
open class Animal(val name: String) {
open fun makeSound() = "???"
}
class Dog(name: String) : Animal(name) {
override fun makeSound() = "Woof!"
}
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!") // метод с реализацией по умолчанию
}
class Button : Clickable {
override fun click() = println("Button clicked")
}
abstract class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
class Car(val engine: Engine, val wheels: List<Wheel>)
Kotlin предоставляет встроенную поддержку шаблона "Композиция через делегирование", который позволяет реализовать интерфейсы, делегируя их методы другому объекту.
interface Base {
fun print()
fun sayHello()
}
// Класс, реализующий интерфейс
class BaseImpl : Base {
override fun print() = println("BaseImpl: print")
override fun sayHello() = println("BaseImpl: hello")
}
// Класс, делегирующий реализацию интерфейса другому объекту
class Derived(b: Base) : Base by b {
// Можно переопределить некоторые методы
override fun print() = println("Derived: print")
}
fun main() {
val base = BaseImpl()
val derived = Derived(base)
derived.print() // "Derived: print" - переопределенный метод
derived.sayHello() // "BaseImpl: hello" - делегированный метод
}
interface Clickable {
fun click()
}
interface Focusable {
fun focus()
}
class Button(
clickHandler: Clickable,
focusHandler: Focusable
) : Clickable by clickHandler, Focusable by focusHandler
interface Worker {
fun work()
fun takeBreak()
}
class DefaultWorker : Worker {
override fun work() = println("Working...")
override fun takeBreak() = println("Taking a break")
}
class LazyWorker(worker: Worker) : Worker by worker {
override fun work() = println("Pretending to work")
// takeBreak() делегируется worker
}
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
object Singleton {
val property = "I'm a singleton"
fun doSomething() = println("Doing something")
}
class MyClass {
companion object {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
data class User(val name: String, val age: Int)
// Автоматически генерируются:
// equals(), hashCode(), toString(), copy(), component1(), component2(), ...
Ограничивают иерархию наследования
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) = when(result) {
is Result.Success -> println("Success: ${result.data}")
is Result.Error -> println("Error: ${result.message}")
is Result.Loading -> println("Loading...")
// Не нужен else, компилятор знает все подклассы
}
class Person {
var name: String = ""
get() = field.uppercase()
set(value) {
field = value.trim()
}
}
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("") {
prop, old, new -> println("$old -> $new")
}
val lazyValue: String by lazy {
println("Computed!")
"Hello"
}
}
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
class Example {
var p: String by Delegate()
}
class Box<T>(val value: T)
val intBox = Box(1)
val stringBox = Box("Hello")
- Инвариантность - по умолчанию:
Box<String>
не является подтипом или супертипомBox<Any>
- Ковариантность (
out
) -Box<String>
является подтипомBox<Any>
- Контравариантность (
in
) -Box<Any>
является подтипомBox<String>
// Ковариантность (out) - можно только возвращать T, но не принимать
class Producer<out T>(private val value: T) {
fun get(): T = value
}
// Контравариантность (in) - можно только принимать T, но не возвращать
class Consumer<in T> {
fun consume(value: T) { /* ... */ }
}
fun <T : Comparable<T>> sort(list: List<T>) { /* ... */ }
Доступ к информации о типе во время выполнения в inline-функциях
inline fun <reified T> isA(value: Any) = value is T
fun main() {
println(isA<String>("abc")) // true
println(isA<Int>("abc")) // false
}
- List - упорядоченная коллекция
- Set - неупорядоченная коллекция уникальных элементов
- Map - набор пар ключ-значение
// Неизменяемые коллекции
val list = listOf(1, 2, 3)
val set = setOf(1, 2, 3)
val map = mapOf("a" to 1, "b" to 2)
// Изменяемые коллекции
val mutableList = mutableListOf(1, 2, 3)
val mutableSet = mutableSetOf(1, 2, 3)
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
// Фильтрация
val filtered = list.filter { it > 1 }
// Преобразование
val doubled = list.map { it * 2 }
// Сортировка
val sorted = list.sorted()
// Группировка
val grouped = list.groupBy { it % 2 }
// Агрегация
val sum = list.sum()
val reduced = list.reduce { acc, i -> acc + i }
val folded = list.fold(0) { acc, i -> acc + i }
// Поиск
val found = list.find { it > 2 }
val any = list.any { it > 2 }
val all = list.all { it > 0 }
Ленивые коллекции, операции выполняются только при необходимости
val sequence = sequenceOf(1, 2, 3, 4, 5)
.filter { it > 2 }
.map { it * 2 }
.toList() // только здесь выполняются операции
// Для data классов
data class Person(val name: String, val age: Int)
val person = Person("Alice", 30)
val (name, age) = person
// Для пар и троек
val pair = Pair("Alice", 30)
val (name, age) = pair
// В циклах
for ((key, value) in mapOf("a" to 1, "b" to 2)) {
println("$key -> $value")
}
val length = str?.let {
// it - это str
it.length
}
val length = str?.run {
// this - это str
length
}
val result = with(str) {
// this - это str
length
}
val person = Person().apply {
// this - это Person
name = "Alice"
age = 30
}
val person = Person("Alice", 30).also {
// it - это Person
println("Created person: ${it.name}")
}
Kotlin отлично подходит для создания предметно-ориентированных языков:
// Пример DSL для создания HTML
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
class HTML {
fun head(init: Head.() -> Unit) { /*...*/ }
fun body(init: Body.() -> Unit) { /*...*/ }
}
// Использование
html {
head {
title("DSL Demo")
}
body {
h1("Hello, Kotlin DSL!")
p("This is a paragraph")
}
}
class Person {
var name = ""
var age = 0
var address = Address()
fun address(init: Address.() -> Unit) {
address.init()
}
}
class Address {
var street = ""
var city = ""
var zipCode = ""
}
fun person(init: Person.() -> Unit): Person {
val person = Person()
person.init()
return person
}
// Использование
val john = person {
name = "John"
age = 25
address {
street = "Main Street"
city = "New York"
zipCode = "10001"
}
}
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
launch(Dispatchers.Default) {
// Выполняется в пуле потоков по умолчанию
}
launch(Dispatchers.IO) {
// Оптимизировано для операций ввода/вывода
}
launch(Dispatchers.Main) {
// Выполняется в главном потоке (для UI)
}
coroutineScope {
val job1 = launch { /* ... */ }
val job2 = launch { /* ... */ }
// Ждет завершения всех корутин
}
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
throw AssertionError("Error in coroutine")
}
job.join()
val supervisor = SupervisorJob()
val scope = CoroutineScope(supervisor + Dispatchers.Default)
scope.launch {
// Ошибка здесь не отменит другие дочерние корутины
}
val channel = Channel<Int>()
launch {
for (i in 1..5) {
channel.send(i)
}
channel.close()
}
for (value in channel) {
println(value)
}
Асинхронные потоки данных
fun simple(): Flow<Int> = flow {
for (i in 1..3) {
delay(100)
emit(i)
}
}
suspend fun main() {
simple().collect { value ->
println(value)
}
}
val flow = flow {
for (i in 1..5) emit(i)
}
flow
.filter { it > 2 }
.map { it * 2 }
.collect { println(it) }
val _stateFlow = MutableStateFlow(0)
val stateFlow = _stateFlow.asStateFlow()
_stateFlow.value = 1 // Обновление значения
@JvmStatic
- для статических методов@JvmField
- для полей без геттеров/сеттеров@JvmOverloads
- для генерации перегруженных методов@Throws
- для объявления исключений
class KotlinClass {
companion object {
@JvmStatic fun staticMethod() { /* ... */ }
}
@JvmField
val directField = "value"
@JvmOverloads
fun method(param1: String, param2: Int = 0) { /* ... */ }
@Throws(IOException::class)
fun riskyMethod() { /* ... */ }
}
// Платформенные типы (могут быть null)
val javaString: String? = JavaClass.returnsString()
// SAM-конверсия
JavaClass.setListener { println("Clicked!") }
// Вызов функций верхнего уровня
String result = MyFileKt.topLevelFunction();
// Вызов методов объекта-синглтона
String data = MySingleton.INSTANCE.getData();
// Вызов методов объекта-компаньона с @JvmStatic
MyClass.staticMethod();
// Объявление аннотации
annotation class Inject
// Использование аннотации
@Inject
class MyService
// Рефлексия
val kClass = MyService::class
val annotations = kClass.annotations
val properties = kClass.memberProperties
@Deprecated("Use newMethod instead", ReplaceWith("newMethod()"))
fun oldMethod() { /*...*/ }
@OptIn(ExperimentalCoroutinesApi::class)
fun experimentalFunction() { /*...*/ }
@RequiresOptIn("This API is experimental")
annotation class ExperimentalAPI
@ExperimentalAPI
fun dangerousFunction() { /*...*/ }
import kotlin.contracts.*
fun String?.isNullOrEmpty(): Boolean {
contract {
returns(false) implies (this@isNullOrEmpty != null)
}
return this == null || this.isEmpty()
}
fun main() {
val name: String? = "John"
if (!name.isNullOrEmpty()) {
// Компилятор знает, что name не null
println(name.length)
}
}
Новая экспериментальная функция в Kotlin 1.6.20+:
// Объявление
context(Logger, Transaction)
fun saveUser(user: User) {
log("Saving user: ${user.name}") // доступ к методу log из Logger
commit() // доступ к методу commit из Transaction
}
// Использование
with(logger) {
with(transaction) {
saveUser(user)
}
}
// Общий код
expect fun getPlatformName(): String
// Платформенно-специфичная реализация для JVM
actual fun getPlatformName(): String = "JVM"
// Платформенно-специфичная реализация для JS
actual fun getPlatformName(): String = "JavaScript"
// Общий код
expect class DateFormatter() {
fun format(date: Date): String
}
// Реализация для JVM
actual class DateFormatter {
private val formatter = SimpleDateFormat("yyyy-MM-dd")
actual fun format(date: Date): String {
return formatter.format(date)
}
}
// Реализация для JS
actual class DateFormatter {
actual fun format(date: Date): String {
return "${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}"
}
}
import kotlinx.cinterop.*
import platform.posix.*
fun main() {
memScoped {
val cString = "Hello from Kotlin/Native!".cstr.ptr
printf("C string: %s\n", cString)
}
}
import kotlinx.cinterop.*
import platform.posix.*
fun main() {
val time = time(null)
val localTime = localtime(cValuesOf(time))?.pointed
if (localTime != null) {
println("Год: ${localTime.tm_year + 1900}")
println("Месяц: ${localTime.tm_mon + 1}")
println("День: ${localTime.tm_mday}")
}
}
import kotlinx.cinterop.*
fun main() {
memScoped {
val buffer = allocArray<ByteVar>(1024)
buffer[0] = 42
println("Значение: ${buffer[0]}")
} // Память освобождается автоматически
}
external fun alert(message: String)
fun main() {
alert("Hello from Kotlin/JS!")
val obj = js("{ name: 'John', age: 30 }")
console.log(obj.name)
}
@JsModule("lodash")
@JsNonModule
external object _ {
fun chunk(array: Array<Int>, size: Int): Array<Array<Int>>
}
fun main() {
val result = _.chunk(arrayOf(1, 2, 3, 4), 2)
console.log(result)
}
external interface ReactProps {
var name: String
}
val Welcome = functionalComponent<ReactProps> { props ->
div {
+"Hello, ${props.name}"
}
}
fun main() {
render(document.getElementById("root")) {
Welcome {
name = "Kotlin"
}
}
}
KSP - это альтернатива KAPT для обработки аннотаций, более эффективная и быстрая.
// Пример аннотации для KSP
@Target(AnnotationTarget.CLASS)
annotation class GenerateFactory
// Использование
@GenerateFactory
class MyService
// В модуле процессора
class MySymbolProcessor : SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver.getSymbolsWithAnnotation("com.example.GenerateFactory")
symbols.forEach { symbol ->
if (symbol is KSClassDeclaration) {
// Генерация кода для аннотированного класса
}
}
return emptyList()
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview
@Composable
fun PreviewGreeting() {
Greeting("Android")
}
@Composable
fun StyledButton(text: String, onClick: () -> Unit) {
Button(
onClick = onClick,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = text)
}
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener {
binding.textView.text = "Button clicked!"
}
}
}
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
fun loadUser(userId: String) {
viewModelScope.launch {
_user.value = repository.getUser(userId)
}
}
}
// Использование в Activity/Fragment
viewModel.user.observe(viewLifecycleOwner) { user ->
binding.userName.text = user.name
}
fun Application.module() {
routing {
get("/") {
call.respondText("Hello, Ktor!")
}
get("/users/{id}") {
val id = call.parameters["id"]
call.respond(userService.getUser(id))
}
}
}
object Users : Table() {
val id = integer("id").autoIncrement().primaryKey()
val name = varchar("name", 50)
val email = varchar("email", 100)
}
transaction {
Users.insert {
it[name] = "John"
it[email] = "[email protected]"
}
}
@RestController
class UserController(private val userService: UserService) {
@GetMapping("/users")
fun getUsers(): List<User> = userService.findAll()
@PostMapping("/users")
fun createUser(@RequestBody user: User): User = userService.save(user)
}
@JvmInline
value class Password(val value: String)
fun validatePassword(password: Password) { /* ... */ }
// Использование
val password = Password("secret")
validatePassword(password)
value class Point(val x: Int, val y: Int) {
fun distanceTo(other: Point): Double {
val dx = x - other.x
val dy = y - other.y
return kotlin.math.sqrt((dx * dx + dy * dy).toDouble())
}
}
// Использование асинхронных коллекций
val list = buildList {
add(1)
add(2)
addAll(listOf(3, 4, 5))
}
// Использование последовательностей для больших наборов данных
val result = sequence {
for (i in 1..1000000) {
yield(i)
}
}
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10)
.toList()
class CalculatorTest {
@Test
fun `2 plus 2 should equal 4`() {
val calculator = Calculator()
assertEquals(4, calculator.add(2, 2))
}
@Test
fun `division by zero should throw exception`() {
val calculator = Calculator()
assertThrows<ArithmeticException> {
calculator.divide(1, 0)
}
}
}
@Test
fun `should call repository when service method is called`() {
// Создание мока
val repository = mockk<UserRepository>()
// Настройка поведения
every { repository.findById(any()) } returns User("1", "John")
// Создание тестируемого объекта с моком
val service = UserService(repository)
// Вызов тестируемого метода
val user = service.getUserById("1")
// Проверки
assertEquals("John", user.name)
verify(exactly = 1) { repository.findById("1") }
}
@Test
fun `test coroutine function`() = runTest {
val result = withContext(Dispatchers.Default) {
delay(1000) // Виртуальное время в тестах
"Result"
}
assertEquals("Result", result)
}
// Ленивая инициализация
val lazyValue: String by lazy {
println("Computed!")
"Hello"
}
// Наблюдаемые свойства
var name: String by Delegates.observable("initial") { prop, old, new ->
println("$old -> $new")
}
// Хранение свойств в Map
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John",
"age" to 25
))
@JvmInline
value class Name(
val first: String,
val last: String
) {
fun fullName() = "$first $last"
}
// Использование
val name = Name("John", "Doe")
println(name.fullName()) // "John Doe"
fun interface Predicate<T> {
fun test(value: T): Boolean
}
// Использование - автоматическое преобразование лямбды
val isEven = Predicate<Int> { it % 2 == 0 }
println(isEven.test(4)) // true
// Включение K2 компилятора в gradle.properties
kotlin.experimental.tryK2=true
// Вывод типов для возвращаемых значений
fun createMap() = buildMap { // Тип выводится как Map<String, Int>
put("one", 1)
put("two", 2)
}
// Функция zip для Map
val map1 = mapOf("a" to 1, "b" to 2)
val map2 = mapOf("a" to "A", "b" to "B")
val zipped = map1.zip(map2) { (k1, v1), (k2, v2) ->
k1 to "$v1-$v2"
}
// Результат: [("a" to "1-A"), ("b" to "2-B")]
// Функция chunked с трансформацией
val numbers = listOf(1, 2, 3, 4, 5)
val sumOfChunks = numbers.chunked(2) { it.sum() }
// Результат: [3, 7, 5]
Эта полная шпаргалка охватывает основные и продвинутые возможности языка Kotlin, включая работу с различными платформами, оптимизации, тестирование и новейшие функции. Она будет полезна как для начинающих, так и для опытных разработчиков Kotlin.