diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..9cffaf9 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,32 @@ +name: Check + +on: + pull_request: + types: [assigned, opened, synchronize, reopened] + +jobs: + checks: + name: Checks + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: set up JDK 17 + uses: actions/setup-java@v1 + with: + java-version: 17 + - name: Cache + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + ~/.m2 + ~/.android/build-cache + key: ${GITHUB_REF##*/} + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Check with gradle + run: ./gradlew build diff --git a/README.md b/README.md index c7da4e3..d7a41ad 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,33 @@ # Kotlin-7 - Generics Код к занятию Kotlin-7 - Generics + +## Домашнее задание +В папке [network](src/main/kotlin/ru/kotlin/homework/network) находится прототип класса +результата работы сетевого сервиса `NetworkResponse`, который может быть: + +- `Success` - для удачного результата +- `Failure` - для ошибки + +### Задание 1. +Исправьте определение классов так, чтобы все присваивания под определениями компилировались +без ошибок. Подсказки: + +- Используйте declaration type variance +- Мы только ВОЗВРАЩАЕМ результат или ошибку (ковариантность по обоим параметрам) +- Вспоминаем, что тип Nothing - это подтип любого другого типа + +### Задание 2. +Почините (правильно расставьте variance параметров) класс [NetworkLogger](src/main/kotlin/ru/kotlin/homework/network/NetworkLogger.kt) +таким образом, чтобы **один** универсальный экземпляр логгера можно было использовать для логирования любых ошибок: + +- `processThrowables` принимает `ErrorLogger` +- `processApiErrors` принимает `ErrorLogger` + +Приступайте ко второму заданию только после окончания работы над первым! + +### Задание 3 (со звездочкой) +Сделайте так, чтобы [NetworkLogger](src/main/kotlin/ru/kotlin/homework/network/NetworkLogger.kt) имел возможность выдать список +накопленных ошибок. Настройте типы таким образом, чтобы при сохранении условий заданий 1 и 2, в классе появилась функция: +```kotlin +fun dump(): List> +``` \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1a97555..e9873b1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ rootProject.name = 'Kotlin7' - diff --git a/src/main/kotlin/ru/kotlin/homework/Colors.kt b/src/main/kotlin/ru/kotlin/homework/Colors.kt new file mode 100644 index 0000000..6556466 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/Colors.kt @@ -0,0 +1,7 @@ +package ru.kotlin.homework + +abstract class Color + +data object Red : Color() +data object Blue : Color() +data object Green : Color() \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/ShapeToColor.kt b/src/main/kotlin/ru/kotlin/homework/ShapeToColor.kt new file mode 100644 index 0000000..516e346 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/ShapeToColor.kt @@ -0,0 +1,39 @@ +@file:Suppress("unused") + +package ru.kotlin.homework + +import java.lang.IllegalArgumentException + +open class ShapeToColor { + open fun process(shape: Shape): Color = when(shape) { + is Square -> Red + is Circle -> Blue + else -> throw IllegalArgumentException("Unknown shape") + } +} + +class CircleToColor : ShapeToColor() { + override fun process(shape: Shape): Color = when(shape) { + is Circle -> Blue + else -> throw IllegalArgumentException("Unknown shape") + } +} + +class NewShapeToColor : ShapeToColor() { + override fun process(shape: Shape): Color = when(shape) { + is Triangle -> Blue + else -> super.process(shape) + } +} + +class NewColors : ShapeToColor() { + override fun process(shape: Shape): Color = when(shape) { + is Triangle -> Blue + is Square -> Green + else -> super.process(shape) + } +} + +class AllInRed : ShapeToColor() { + override fun process(shape: Shape): Color = Red +} \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/Shapes.kt b/src/main/kotlin/ru/kotlin/homework/Shapes.kt new file mode 100644 index 0000000..0d95ddb --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/Shapes.kt @@ -0,0 +1,11 @@ +package ru.kotlin.homework + +import kotlin.random.Random + +abstract class Shape { + val id: Int = Random.nextInt() +} + +data object Square: Shape() +data object Circle: Shape() +data object Triangle: Shape() \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/coVarianceInKotlin.kt b/src/main/kotlin/ru/kotlin/homework/coVarianceInKotlin.kt new file mode 100644 index 0000000..2e908a6 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/coVarianceInKotlin.kt @@ -0,0 +1,19 @@ +package ru.kotlin.homework + + +fun main() { + val producer: ShapeProducer = CircleProducer() + println(producer.produce()) +} + +open class ShapeProducer { + open fun produce(): Shape { + return Square + } +} + +class CircleProducer : ShapeProducer() { + override fun produce(): Circle { + return Circle + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/contrvarianceInKotlin.kt b/src/main/kotlin/ru/kotlin/homework/contrvarianceInKotlin.kt new file mode 100644 index 0000000..1588223 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/contrvarianceInKotlin.kt @@ -0,0 +1,22 @@ +package ru.kotlin.homework + +fun main() { + val processor: ToExtendCircle = ToExtendShape() + processor.process(Circle) + + val shapeProcessor: ToExtendShape = processor as ToExtendShape + shapeProcessor.process(Square) +} + +open class ToExtendCircle { + open fun process(value: Circle) { + println(value) + } +} + +class ToExtendShape : ToExtendCircle() { + fun process(value: Shape) = when(value) { + is Circle -> super.process(value) + else -> println("Any: $value") + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/generics.kt b/src/main/kotlin/ru/kotlin/homework/generics.kt new file mode 100644 index 0000000..ed80015 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/generics.kt @@ -0,0 +1,18 @@ +@file:Suppress("RedundantExplicitType") + +package ru.kotlin.homework + +import java.lang.IllegalArgumentException + +private val matcher: ShapeToColor = AllInRed() + +fun main() { + println("Square: ${process(Square)}") + println("Circle: ${process(Circle)}") +} + +fun process(shape: Shape) = when(matcher.process(shape)) { + Red -> "Красный" + Blue -> "Голубой" + else -> throw IllegalArgumentException("Неизвестный цвет") +} \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/inOut.kt b/src/main/kotlin/ru/kotlin/homework/inOut.kt new file mode 100644 index 0000000..b60b5b2 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/inOut.kt @@ -0,0 +1,61 @@ +package ru.kotlin.homework + + +fun main() { + val circleGroup = Group() + circleGroup.insert(Circle) + val fromGroup = circleGroup.fetch() + println("From group: $fromGroup") + + val readGroup: Group = circleGroup + val fromReadGroup: Shape = readGroup.fetch() + println("From read group: $fromReadGroup") + fetcher(circleGroup) + + val shapeGroup = Group() + val writeCircleGroup: Group = shapeGroup + writeCircleGroup.insert(Circle) + val writeTriangleGroup: Group = shapeGroup + writeTriangleGroup.insert(Triangle) + putter(shapeGroup, Circle) + + val fromShapeGroup: Shape = shapeGroup.fetch() + println("From shape group: $fromShapeGroup") + + var anyGroup: Group<*> = circleGroup + println(measure(anyGroup)) + anyGroup = readGroup + println(measure(anyGroup)) + anyGroup = shapeGroup + println(measure(anyGroup)) + + idOfFetched(anyGroup) +} + +open class Group { + private val items: MutableList = mutableListOf() + + fun getSize(): Int = items.size + + fun insert(item: T) { + items.add(item) + } + fun fetch(): T { + return items.last() + } +} + +fun fetcher(group: Group) { + val fetched = group.fetch() + println(fetched) +} +fun putter(group: Group, item: Circle) { + group.insert(item) +} +fun measure(group: Group<*>) { + println("Size of group: ${group.getSize()}") +} +fun idOfFetched(group: Group<*>) { + val fetched: Shape = group.fetch() + println("Id of fetched: ${fetched.id}") +} \ No newline at end of file diff --git a/src/main/kotlin/ru/kotlin/homework/network/NetworkLogger.kt b/src/main/kotlin/ru/kotlin/homework/network/NetworkLogger.kt new file mode 100644 index 0000000..007f762 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/network/NetworkLogger.kt @@ -0,0 +1,66 @@ +@file:Suppress("unused") + +package ru.kotlin.homework.network + +import ru.kotlin.homework.Circle +import java.lang.IllegalArgumentException +import java.time.LocalDateTime + +/** + * Известный вам список ошибок + */ +sealed class ApiException(message: String) : Throwable(message) { + data object NotAuthorized : ApiException("Not authorized") + data object NetworkException : ApiException("Not connected") + data object UnknownException: ApiException("Unknown exception") +} + +class ErrorLogger { + + private val errors = mutableListOf>() + + fun log(response: NetworkResponse<*, E>) { + if (response is Failure) { + errors.add(response.responseDateTime to response.error) + } + } + + fun dumpLog() { + errors.forEach { (date, error) -> + println("Error at $date: ${error.message}") + } + } + + fun dump(): List> = errors +} + +fun processThrowables(logger: ErrorLogger) { + logger.log(Success("Success")) + Thread.sleep(100) + logger.log(Success(Circle)) + Thread.sleep(100) + logger.log(Failure(IllegalArgumentException("Something unexpected"))) + + logger.dumpLog() +} + +fun processApiErrors(apiExceptionLogger: ErrorLogger) { + apiExceptionLogger.log(Success("Success")) + Thread.sleep(100) + apiExceptionLogger.log(Success(Circle)) + Thread.sleep(100) + apiExceptionLogger.log(Failure(ApiException.NetworkException)) + + apiExceptionLogger.dumpLog() +} + +fun main() { + val logger = ErrorLogger() + + println("Processing Throwable:") + processThrowables(logger) + + println("Processing Api:") + processApiErrors(logger) +} + diff --git a/src/main/kotlin/ru/kotlin/homework/network/NetworkResponse.kt b/src/main/kotlin/ru/kotlin/homework/network/NetworkResponse.kt new file mode 100644 index 0000000..74b5ec0 --- /dev/null +++ b/src/main/kotlin/ru/kotlin/homework/network/NetworkResponse.kt @@ -0,0 +1,45 @@ +@file:Suppress("unused") + +package ru.kotlin.homework.network + +import java.lang.Exception +import java.lang.IllegalArgumentException +import java.time.LocalDateTime + +/** + * Network result + */ +sealed class NetworkResponse { + val responseDateTime: LocalDateTime = LocalDateTime.now() +} + +/** + * Network success + */ +data class Success(val resp: T): NetworkResponse() + +/** + * Network error + */ +data class Failure(val error: R): NetworkResponse() + +val s1 = Success("Message") +val r11: NetworkResponse = s1 +val r12: NetworkResponse = s1 + +val s2 = Success("Message") +val r21: NetworkResponse = s2 +val r22: NetworkResponse = s2 + +val s3 = Success(String()) +val r31: Success = s3 +val r32: Success = s3 + +val e = Failure(Error()) +val er1: NetworkResponse = e +val er2: NetworkResponse = e +val er4: NetworkResponse = e + +val er5: NetworkResponse = Failure(IllegalArgumentException("message")) + +val message = e.error.message