Added kotlin guide. (WIP) (15.10.26)

This commit is contained in:
2026-10-15 00:24:21 +03:00
parent dc82207723
commit da3ad9dd1a
13 changed files with 2120 additions and 0 deletions
@@ -0,0 +1,129 @@
---
title: Пакеты и импорты
description: Объявление пакетов, импорты, псевдонимы и автоматически импортируемые пакеты
tags:
- kotlin
- syntax
---
## Пакет
Объявляется первой строкой файла:
```kotlin
package com.example.app
fun helper() { }
class Service
```
Полное имя функции - `com.example.app.helper`.
Отличие от Java: **структура каталогов не обязана совпадать с пакетом**, и имя файла не связано с содержимым. Компилятор не возражает. На практике соглашение соблюдают: иначе навигация по проекту ломается.
Файл без `package` попадает в корневой пакет (default package).
## Содержимое файла
В одном файле может быть сколько угодно объявлений верхнего уровня:
```kotlin
package com.example
const val VERSION = "1.0"
fun parse(text: String): Int = text.toInt()
class User(val name: String)
class Admin(val name: String)
private fun internalHelper() { } // видна только в этом файле
```
Никаких `public class` на файл - ограничения «один публичный класс на файл» в Kotlin нет.
## Импорты
```kotlin
import com.example.app.Service // конкретный класс
import com.example.app.helper // функция верхнего уровня
import com.example.app.* // всё из пакета
import com.example.app.User.Companion.create // член companion object
```
Импортировать можно не только типы, но и функции, свойства, enum-константы - всё, что объявлено на верхнем уровне или как статический член.
```kotlin
import kotlin.math.PI
import kotlin.math.sqrt
fun main() {
println(sqrt(PI)) // 1.7724538509055159
}
```
## Псевдонимы - as
Когда имена конфликтуют или слишком длинные:
```kotlin
import com.example.data.User as DataUser
import com.example.api.User as ApiUser
fun convert(u: DataUser): ApiUser = ApiUser(u.name)
```
Псевдоним действует только в своём файле. Если нужно имя на весь модуль - это [typealias](../Базовые%20типы%20ООП/Typealias.md).
## Импортируются автоматически
Эти пакеты доступны без `import`:
| Пакет | Что содержит |
|---|---|
| `kotlin.*` | `Int`, `String`, `Any`, базовые функции |
| `kotlin.annotation.*` | аннотации |
| `kotlin.collections.*` | `List`, `Map`, `listOf`, операции |
| `kotlin.comparisons.*` | `compareBy`, `maxOf` |
| `kotlin.io.*` | `println`, `readln` |
| `kotlin.ranges.*` | диапазоны, `step`, `downTo` |
| `kotlin.sequences.*` | `Sequence`, `sequenceOf` |
| `kotlin.text.*` | операции со строками |
| `java.lang.*` | только на JVM |
| `kotlin.jvm.*` | только на JVM |
Поэтому `println`, `listOf`, `Int` работают из коробки. А `kotlin.math.sqrt` - нет, его импортируют явно.
## Видимость на верхнем уровне
```kotlin
public fun api() { } // видна везде (public — по умолчанию)
internal fun moduleOnly() { } // видна в своём модуле
private fun fileOnly() { } // видна только в этом файле
```
`protected` на верхнем уровне запрещён - нет класса, от которого наследоваться.
Подробнее: [Модификаторы видимости](../../ООП/Модификаторы%20видимости.md)
## Имя класса-обёртки
Функции верхнего уровня попадают в класс, названный по файлу: `Utils.kt` → класс `UtilsKt`. Имя можно задать:
```kotlin
@file:JvmName("Utils")
package com.example
fun helper() { } // из Java: Utils.helper()
```
Аннотации уровня файла ставятся **до** `package`. Подробнее: [Kotlin из Java](../../Взаимодействие%20с%20Java/Kotlin%20из%20Java.md)
> [!info] Отличия от Java
> | Java | Kotlin |
> |---|---|
> | каталоги обязаны совпадать с пакетом | не обязаны (но так принято) |
> | имя файла = имя публичного класса | имя файла произвольно |
> | один публичный класс на файл | сколько угодно объявлений |
> | `import static` для статики | обычный `import` для всего |
> | псевдонимов нет | `import ... as Name` |
> | автоимпорт только `java.lang` | десять пакетов `kotlin.*` |
> | `package-private` по умолчанию | `public` по умолчанию |
>
> Последняя строка важна: в Java класс без модификатора виден только своему пакету, в Kotlin - всем. Для сокрытия внутренностей библиотеки используют `internal`.
> [!warning] Подводные камни
> **Нет аналога package-private.** `internal` ограничивает *модулем* (единицей компиляции Gradle), а не пакетом. Разделить код на пакеты и спрятать их друг от друга внутри одного модуля нельзя - только разносить по модулям.
>
> **`import *` не затягивает вложенные пакеты.** `import com.example.*` не даёт доступа к `com.example.data.User`.
>
> **Конфликт импортов - ошибка компиляции, а не предупреждение.** Два `User` из разных пакетов требуют `as` или полного имени.
>
> **Функции с одинаковым именем в разных файлах одного пакета конфликтуют.** Два `private fun helper()` в разных файлах - нормально, а два `fun helper()` с одной сигнатурой - ошибка: оба попадают в один пакет.
>
> **`@file:JvmName` не действует, если имя файла совпадает с именем класса в нём.** Коллизия имён вызовет ошибку компиляции.
Дополнительно: [Структура проекта](../../Инструментарий/Структура%20проекта.md)
Далее: [Null-безопасность](../Null-безопасность/Null-безопасность.md)