Осознанная оптимизация Compose 2: В борьбе с композицией
Jetpack Compose постоянно развивается, открывая перед разработчиками новые горизонты для оптимизации. С момента нашего последнего обзора, мы добились значительного прогресса, сократив задержки при скролле с 5-7% до нуля. В этом материале мы поделимся свежими находками и передовыми практиками в оптимизации Compose. Чтобы максимально углубиться в тему, рекомендуем ознакомиться с первой частью.
Читать статью
Jetpack Compose постоянно развивается, открывая перед разработчиками новые горизонты для оптимизации. С момента нашего последнего обзора, мы добились значительного прогресса, сократив задержки при скролле с 5-7% до нуля. В этом материале мы поделимся свежими находками и передовыми практиками в оптимизации Compose. Чтобы максимально углубиться в тему, рекомендуем ознакомиться с первой частью.
Читать статью
Teletype
Осознанная оптимизация Compose 2: В борьбе с композицией
Jetpack Compose постоянно развивается, открывая перед разработчиками новые горизонты для оптимизации. С момента нашего последнего...
Пару слов о полях и свойствах в Kotlin
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить поле. Все — свойства! Однако, во избежании путаницы, я предпочитаю разделять определения полей и свойств на следующей основе — полями являются приватные переменные-члены класса. Это то, для чего выделена память. Свойствами являются публичные или защищенные (protected) функциями геттеры и сеттеры, которые позволяют вам получить доступ к приватным полям.
Я считаю хорошей идеей разграничивать эти понятия таким образом, потому что это способствует моему пониманию, а также упрощает объяснение связанных с этим вещей.
Читать статью
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить поле. Все — свойства! Однако, во избежании путаницы, я предпочитаю разделять определения полей и свойств на следующей основе — полями являются приватные переменные-члены класса. Это то, для чего выделена память. Свойствами являются публичные или защищенные (protected) функциями геттеры и сеттеры, которые позволяют вам получить доступ к приватным полям.
Я считаю хорошей идеей разграничивать эти понятия таким образом, потому что это способствует моему пониманию, а также упрощает объяснение связанных с этим вещей.
Читать статью
Teletype
Пару слов о полях и свойствах в Kotlin
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить...
Kotlin вместо bash. Прокачиваем автоматизацию на сервере
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps чаще всего используются или bash-сценарии или python. Первое решение косвенно используется и в описании Dockerfile, поскольку сценарий исполняемых команд принципиально ничем не отличается от запуска скрипта в какой-либо shell, второй подход чаще ассоциируется с автоматизацией, связанных с взаимодействием с хранилищами данных. Но несправедливо было бы обойти стороной возможность создания исполняемых сценариев на языке Kotlin, которые могут стать полноценной заменой bash-сценариям.
В этой статье мы рассмотрим несколько примеров использования Kotlin Scripting (KTS) для автоматизации в распределенной системе, будем использовать долгоживущие скрипты с ожиданием заданий через RabbitMQ, а также поработаем с файловой системой, внешними сервисами, а также попробуем использовать KTS для сборки Docker-контейнеров.
Читать статью
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps чаще всего используются или bash-сценарии или python. Первое решение косвенно используется и в описании Dockerfile, поскольку сценарий исполняемых команд принципиально ничем не отличается от запуска скрипта в какой-либо shell, второй подход чаще ассоциируется с автоматизацией, связанных с взаимодействием с хранилищами данных. Но несправедливо было бы обойти стороной возможность создания исполняемых сценариев на языке Kotlin, которые могут стать полноценной заменой bash-сценариям.
В этой статье мы рассмотрим несколько примеров использования Kotlin Scripting (KTS) для автоматизации в распределенной системе, будем использовать долгоживущие скрипты с ожиданием заданий через RabbitMQ, а также поработаем с файловой системой, внешними сервисами, а также попробуем использовать KTS для сборки Docker-контейнеров.
Читать статью
Teletype
Kotlin вместо bash. Прокачиваем автоматизацию на сервере
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps (которые, кроме всего прочего, нередко...
Что такое мульти-декларации (destructuring declarations)?
Мульти-декларации (destructuring declarations или деструктуризирующее присваивание) — это способ извлечения значений из объекта и присвоения их сразу нескольким переменным. В Kotlin этот механизм поддерживается с помощью оператора распаковки (destructuring operator) — componentN(), где N — номер компонента.
При создании data класса Kotlin автоматически создает функции componentN() для каждого свойства класса, где N — номер позиции переменной в конструкторе. Функции componentN() возвращают значения свойств в порядке их объявления в конструкторе. Это позволяет использовать мульти-декларации для распаковки значений свойств и присваивания их отдельным переменным.
Например, если у нас есть data класс Person с двумя свойствами name и age, мы можем использовать мульти-декларации, чтобы извлечь эти свойства и присвоить их двум переменным:
Мульти-декларации (destructuring declarations или деструктуризирующее присваивание) — это способ извлечения значений из объекта и присвоения их сразу нескольким переменным. В Kotlin этот механизм поддерживается с помощью оператора распаковки (destructuring operator) — componentN(), где N — номер компонента.
При создании data класса Kotlin автоматически создает функции componentN() для каждого свойства класса, где N — номер позиции переменной в конструкторе. Функции componentN() возвращают значения свойств в порядке их объявления в конструкторе. Это позволяет использовать мульти-декларации для распаковки значений свойств и присваивания их отдельным переменным.
Например, если у нас есть data класс Person с двумя свойствами name и age, мы можем использовать мульти-декларации, чтобы извлечь эти свойства и присвоить их двум переменным:
data class Person(val name: String, val age: Int)
val person = Person("Alice", 29)
val (name, age) = person
println(name) // Alice
println(age) // 29
Также можно использовать мульти-декларации в циклах, чтобы итерироваться по спискам объектов и распаковывать значения свойств:
val people = listOf(Person("Alice", 30), Person("Bob", 40))
for ((name, age) in people) {
println("$name is $age years old")
}
// Alice is 30 years old
// Bob is 40 years old
Мульти-декларации также могут быть использованы с массивами и другими коллекциями:val list = listOf("apple", "banana", "orange")
val (first, second, third) = list
println(first) // apple
println(second) // banana
println(third) // orangeСтроим мосты: подключение зависимостей с Cocoapods в Kotlin Multiplatform Mobile
При создании КММ проекта Android Studio предоставляет разработчику выбор между использованием Regular Framework и Cocoapods Dependency Manager для добавления iOS-специфических библиотек, который может быть крайне неочевидным на первый взгляд, ведь использование Regular Framework кажется затруднительным и не пользуется популярностью в отличие от удобного Cocoapods. В данной статье мы рассмотрим, как интегрировать Cocoapods в разработку, создав небольшое Android приложение.
Читать статью
При создании КММ проекта Android Studio предоставляет разработчику выбор между использованием Regular Framework и Cocoapods Dependency Manager для добавления iOS-специфических библиотек, который может быть крайне неочевидным на первый взгляд, ведь использование Regular Framework кажется затруднительным и не пользуется популярностью в отличие от удобного Cocoapods. В данной статье мы рассмотрим, как интегрировать Cocoapods в разработку, создав небольшое Android приложение.
Читать статью
Teletype
Строим мосты: подключение зависимостей с Cocoapods в Kotlin Multiplatform Mobile
При создании КММ проекта Android Studio предоставляет разработчику выбор между использованием Regular Framework и Cocoapods Dependency...
Как адаптировать Android-приложение под Huawei
Всем привет! Меня зовут Миша Вассер, я Head of Android в AGIMA. Мы занимаемся разработкой Digital-продуктов для больших и маленьких компаний, в том числе пилим мобильные приложения.
Не так давно — по сравнению со всей историей Android — Huawei выкатил собственную операционную систему и сказал: «Ребята, вот вам новая система, кайфуйте». Многие отнеслись к новой ОС скептически. Остальным пришлось адаптировать под нее свои Android-приложения.
Мы оказались во второй группе. К нам время от времени обращаются с просьбой помочь с адаптацией под Huawei. И мы неплохо в этом вопросе прокачались. Поэтому сейчас расскажу, что надо сделать, чтобы стало хорошо. А покажу всё это на примере крупного ретейлера, с которым мы работаем.
Читать статью
Всем привет! Меня зовут Миша Вассер, я Head of Android в AGIMA. Мы занимаемся разработкой Digital-продуктов для больших и маленьких компаний, в том числе пилим мобильные приложения.
Не так давно — по сравнению со всей историей Android — Huawei выкатил собственную операционную систему и сказал: «Ребята, вот вам новая система, кайфуйте». Многие отнеслись к новой ОС скептически. Остальным пришлось адаптировать под нее свои Android-приложения.
Мы оказались во второй группе. К нам время от времени обращаются с просьбой помочь с адаптацией под Huawei. И мы неплохо в этом вопросе прокачались. Поэтому сейчас расскажу, что надо сделать, чтобы стало хорошо. А покажу всё это на примере крупного ретейлера, с которым мы работаем.
Читать статью
Telegraph
Как адаптировать Android-приложение под Huawei
Всем привет! Меня зовут Миша Вассер, я Head of Android в AGIMA. Мы занимаемся разработкой Digital-продуктов для больших и маленьких компаний, в том числе пилим мобильные приложения. Не так давно — по сравнению со всей историей Android — Huawei выкатил собственную…
Context receivers — новые extension functions
Поговорим сегодня про context receivers — фиче Kotlin, про которую я узнал давно, но смог найти применение лишь пару месяцев назад. Расскажу о том, что такое context receivers, где их можно использовать, и, конечно же, про «успешный успех» — минус 60% самописного DI в OzonID SDK. Но обо всём по порядку.
Читать статью
Поговорим сегодня про context receivers — фиче Kotlin, про которую я узнал давно, но смог найти применение лишь пару месяцев назад. Расскажу о том, что такое context receivers, где их можно использовать, и, конечно же, про «успешный успех» — минус 60% самописного DI в OzonID SDK. Но обо всём по порядку.
Читать статью
Teletype
Context receivers — новые extension functions
Думаю, не раскрою большой секрет, что Ozon разработал энное количество мобильных приложений: для покупателей, для продавцов, банк...
Во что компилируется typealias?
Typealias не создает новый тип данных, а только создает псевдоним для существующего типа. При компиляции кода, все typealias заменяются на соответствующий тип, поэтому typealias не приводит к увеличению размера кода.
Например, typealias IntPredicate = (Int) -> Boolean при компиляции будет заменено на (Int) -> Boolean, то есть функцию, принимающую значение типа Int и возвращающую значение типа Boolean.
Можно ли использовать typealias для функциональных типов?
Да, можно использовать typealias для функциональных типов в Kotlin. Например, вы можете создать псевдоним для типа функции, которая принимает два параметра типа Int и возвращает значение типа String, следующим образом:
Typealias не создает новый тип данных, а только создает псевдоним для существующего типа. При компиляции кода, все typealias заменяются на соответствующий тип, поэтому typealias не приводит к увеличению размера кода.
Например, typealias IntPredicate = (Int) -> Boolean при компиляции будет заменено на (Int) -> Boolean, то есть функцию, принимающую значение типа Int и возвращающую значение типа Boolean.
Можно ли использовать typealias для функциональных типов?
Да, можно использовать typealias для функциональных типов в Kotlin. Например, вы можете создать псевдоним для типа функции, которая принимает два параметра типа Int и возвращает значение типа String, следующим образом:
typealias IntToString = (Int, Int) -> StringЭто позволит вам использовать созданный псевдоним вместо полного объявления типа, то есть вместо:
fun processValues(f: (Int, Int) -> String) {
// ...
}
можно использовать:fun processValues(f: IntToString) {
// ...
}
Как и в случае с другими typealias, компилятор Kotlin просто заменяет псевдоним на соответствующий тип при компиляции кода.Какие коллекции есть в Kotlin?
Коллекция — это объект, содержащий в себе набор значений одного или различных типов, а также позволяющий к этим значениям обращаться и извлекать. Другими словами — это контейнер, в который вы можете помещать то, что вам нужно, а затем каким-либо образом с ним взаимодействовать. В Kotlin есть три типа коллекций:
• List (список). Упорядоченная коллекция, в которой к элементам можно обращаться по их индексам. Идентичные элементы (дубликаты) могут встречаться в списке более одного раза. Примером списка является предложение: это группа слов, их порядок важен, и они могут повторяться.
• Set (множество/набор). Неупорядоченная коллекция без повторяющихся значений. Примером множества является алфавит.
• Map (словарь/ассоциативный список). Набор из пар "ключ-значение". Ключи уникальны и каждый из них соответствует ровно одному значению. В коллекции могут присутствовать повторяющиеся значения, но не повторяющиеся ключи. Пример — ID сотрудников и их должностей. Map не является наследником интерфейса Collection.
Два типа интерфейсов, на основе которых создаются коллекции:
1. Неизменяемый (read-only) — дают доступ только для чтения (Set, List, Map, Collection).
2. Изменяемый (mutable) — расширяет предыдущий интерфейс и дополнительно даёт доступ к операциям добавления, удаления и обновления элементов коллекции (
Коллекция — это объект, содержащий в себе набор значений одного или различных типов, а также позволяющий к этим значениям обращаться и извлекать. Другими словами — это контейнер, в который вы можете помещать то, что вам нужно, а затем каким-либо образом с ним взаимодействовать. В Kotlin есть три типа коллекций:
• List (список). Упорядоченная коллекция, в которой к элементам можно обращаться по их индексам. Идентичные элементы (дубликаты) могут встречаться в списке более одного раза. Примером списка является предложение: это группа слов, их порядок важен, и они могут повторяться.
• Set (множество/набор). Неупорядоченная коллекция без повторяющихся значений. Примером множества является алфавит.
• Map (словарь/ассоциативный список). Набор из пар "ключ-значение". Ключи уникальны и каждый из них соответствует ровно одному значению. В коллекции могут присутствовать повторяющиеся значения, но не повторяющиеся ключи. Пример — ID сотрудников и их должностей. Map не является наследником интерфейса Collection.
Два типа интерфейсов, на основе которых создаются коллекции:
1. Неизменяемый (read-only) — дают доступ только для чтения (Set, List, Map, Collection).
2. Изменяемый (mutable) — расширяет предыдущий интерфейс и дополнительно даёт доступ к операциям добавления, удаления и обновления элементов коллекции (
MutableSet, MutableList, MutableMap, MutableCollection).Все, что вам нужно знать о Kotlin Multiplatform
Kotlin Multiplatform — это набор для разработки программного обеспечения, который значительно лучше других вариантов разработки кроссплатформенных приложений. В этом руководстве по Kotlin multiplatform вы подробно узнаете все об этом наборе.
Читать статью
Kotlin Multiplatform — это набор для разработки программного обеспечения, который значительно лучше других вариантов разработки кроссплатформенных приложений. В этом руководстве по Kotlin multiplatform вы подробно узнаете все об этом наборе.
Читать статью
Teletype
Все, что вам нужно знать о Kotlin Multiplatform
Kotlin Multiplatform — это набор для разработки программного обеспечения, который значительно лучше других вариантов разработки...
Промежуточные (intermediate) и терминальные (terminal) операции в Sequences
Sequence представляет собой последовательность элементов, которые можно обрабатывать по одному или несколько штук сразу. Обработка элементов Sequence происходит с помощью функций высшего порядка, которые называются операциями.
Операции над Sequence можно разделить на две категории: промежуточные (intermediate) и терминальные (terminal).
Промежуточные операции (intermediate) — это операции, которые возвращают новую Sequence.
Они не выполняются немедленно, а лишь формируют новую последовательность элементов на основе исходной. Промежуточные операции не приводят к запуску вычислений, а готовят данные для последующих операций. Примеры:
filter(predicate: (T) -> Boolean): фильтрует элементы по заданному условию и возвращает новую Sequence
map(transform: (T) -> R): преобразует каждый элемент в новый элемент типа R и возвращает новую Sequence
sortedBy(selector: (T) -> R?): сортирует элементы по заданному ключу и возвращает новую Sequence
Терминальные операции (terminal) — это операции, которые выполняются немедленно и возвращают результат (не Sequence).
Терминальные операции могут быть вызваны только после всех промежуточных операций, так как они завершают последовательность и начинают вычисление результатов на основе всей последовательности, полученной после выполнения всех промежуточных операций. Если же терминальная операция вызывается до выполнения всех промежуточных операций, то она не будет иметь доступа к полной последовательности и вернет неполный результат. Примеры:
toList(): преобразует Sequence в список
toSet(): преобразует Sequence в множество
count(): возвращает количество элементов в Sequence
forEach(action: (T) -> Unit): выполняет действие для каждого элемента Sequence
ВАЖНО: вычисления запускаются только при вызове терминальной функции (до этого момента никаких вычислений не производится).
Sequence представляет собой последовательность элементов, которые можно обрабатывать по одному или несколько штук сразу. Обработка элементов Sequence происходит с помощью функций высшего порядка, которые называются операциями.
Операции над Sequence можно разделить на две категории: промежуточные (intermediate) и терминальные (terminal).
Промежуточные операции (intermediate) — это операции, которые возвращают новую Sequence.
Они не выполняются немедленно, а лишь формируют новую последовательность элементов на основе исходной. Промежуточные операции не приводят к запуску вычислений, а готовят данные для последующих операций. Примеры:
filter(predicate: (T) -> Boolean): фильтрует элементы по заданному условию и возвращает новую Sequence
map(transform: (T) -> R): преобразует каждый элемент в новый элемент типа R и возвращает новую Sequence
sortedBy(selector: (T) -> R?): сортирует элементы по заданному ключу и возвращает новую Sequence
Терминальные операции (terminal) — это операции, которые выполняются немедленно и возвращают результат (не Sequence).
Терминальные операции могут быть вызваны только после всех промежуточных операций, так как они завершают последовательность и начинают вычисление результатов на основе всей последовательности, полученной после выполнения всех промежуточных операций. Если же терминальная операция вызывается до выполнения всех промежуточных операций, то она не будет иметь доступа к полной последовательности и вернет неполный результат. Примеры:
toList(): преобразует Sequence в список
toSet(): преобразует Sequence в множество
count(): возвращает количество элементов в Sequence
forEach(action: (T) -> Unit): выполняет действие для каждого элемента Sequence
ВАЖНО: вычисления запускаются только при вызове терминальной функции (до этого момента никаких вычислений не производится).
Kotlin: взгляд изнутри — преимущества, недостатки и особенности
Всем привет! На связи Сергей Керенцев, Android-разработчик Студии Олега Чулакова на проектах Сбера.
В данной статье мы углубимся в мир Kotlin, рассмотрим его основные преимущества, недостатки и особенности. Мы обойдем такие важные аспекты, как безопасность работы с null-значениями, гибкость типизации с помощью Generics, возможности расширения функциональности с помощью extension-функций, inline-функции, а также многое другое.
Давайте начнем наше увлекательное путешествие в мир Kotlin и раскроем его потенциал!
Читать статью
Всем привет! На связи Сергей Керенцев, Android-разработчик Студии Олега Чулакова на проектах Сбера.
В данной статье мы углубимся в мир Kotlin, рассмотрим его основные преимущества, недостатки и особенности. Мы обойдем такие важные аспекты, как безопасность работы с null-значениями, гибкость типизации с помощью Generics, возможности расширения функциональности с помощью extension-функций, inline-функции, а также многое другое.
Давайте начнем наше увлекательное путешествие в мир Kotlin и раскроем его потенциал!
Читать статью
Teletype
Kotlin: взгляд изнутри — преимущества, недостатки и особенности
Всем привет! На связи Сергей, Android-разработчик Студии Олега Чулакова на проектах Сбера.
Kotlin Multiplatform в ОС Аврора
В данной статье описана работа ОС Аврора с технологией Kotlin Multiplatform. Рассматривается метод подключения модуля Kotlin Multiplatform к приложению на Qt/QML. Для демонстрации было портировано уже существующие демо приложение "KMM RSS Reader". Проведены тесты производительности.
Читать статью
В данной статье описана работа ОС Аврора с технологией Kotlin Multiplatform. Рассматривается метод подключения модуля Kotlin Multiplatform к приложению на Qt/QML. Для демонстрации было портировано уже существующие демо приложение "KMM RSS Reader". Проведены тесты производительности.
Читать статью
Teletype
Kotlin Multiplatform в ОС Аврора
Kotlin Multiplatform — технология, позволяющая объединять бизнес-логику для приложений разных платформ. В ней доступен полный контроль...
Что такое функциональный тип, какие у него ограничения?
Язык Kotlin допускает объявлять тип анонимных функций или лямбда выражений — функциональный.
Функциональный тип — это тип данных, который позволяет работать с функциями как с обычными объектами, передавать функции в качестве аргументов и возвращать их из функций. Синтаксис функционального типа в Котлин представлен списком типов параметров, разделенных запятой, затем оператором -> и типом возвращаемого значения функции.
Пример функционального типа: (a: Int, b: Int) -> Int
Здесь функциональный тип описывает функцию с двумя параметрами типа Int и возвращаемым значением типа Int.
Функциональный тип может быть использован для создания переменных, которые могут хранить ссылки на функции. А также поддерживает перегрузку, что позволяет иметь несколько функций с различными сигнатурами, но с одинаковым именем.
Ограничения функционального типа:
• Тип передаваемой функции должен быть определен явно, чтобы компилятор мог проверить типы аргументов и возвращаемых значений.
• Функциональный тип может содержать только один тип возвращаемого значения.
• Функциональный тип не может содержать более 22 параметров из-за ограничения JVM.
• Функциональный тип не поддерживает неявные преобразования типов.
Несмотря на эти ограничения, функциональные типы позволяют обрабатывать функции как объекты, что повышает гибкость и выразительность кода. Пример определения функционального типа:
Язык Kotlin допускает объявлять тип анонимных функций или лямбда выражений — функциональный.
Функциональный тип — это тип данных, который позволяет работать с функциями как с обычными объектами, передавать функции в качестве аргументов и возвращать их из функций. Синтаксис функционального типа в Котлин представлен списком типов параметров, разделенных запятой, затем оператором -> и типом возвращаемого значения функции.
Пример функционального типа: (a: Int, b: Int) -> Int
Здесь функциональный тип описывает функцию с двумя параметрами типа Int и возвращаемым значением типа Int.
Функциональный тип может быть использован для создания переменных, которые могут хранить ссылки на функции. А также поддерживает перегрузку, что позволяет иметь несколько функций с различными сигнатурами, но с одинаковым именем.
Ограничения функционального типа:
• Тип передаваемой функции должен быть определен явно, чтобы компилятор мог проверить типы аргументов и возвращаемых значений.
• Функциональный тип может содержать только один тип возвращаемого значения.
• Функциональный тип не может содержать более 22 параметров из-за ограничения JVM.
• Функциональный тип не поддерживает неявные преобразования типов.
Несмотря на эти ограничения, функциональные типы позволяют обрабатывать функции как объекты, что повышает гибкость и выразительность кода. Пример определения функционального типа:
// определение функционального типаКод из примера определяет функциональный тип Operation, который представляет собой функцию, принимающую два аргумента типа Int и возвращающую значение типа Int. Затем создается функция calculate, которая принимает три параметра: функцию op типа Operation и два аргумента типа Int. Внутри функции calculate вызывается переданная функция op с переданными аргументами a и b, и результат возвращается из функции calculate. В конце кода создается переменная sum, которая содержит лямбда-выражение, реализующее операцию сложения. Далее вызывается функция calculate с параметрами sum, 10 и 5, что приводит к вызову функции sum с аргументами 10 и 5, и результатом является число 15.
typealias Operation = (Int, Int) -> Int
// использование функционального типа
fun calculate(op: Operation, a: Int, b: Int): Int {
return op(a, b)
}
// пример вызова функции calculate
val sum: Operation = { x, y -> x + y }
calculate(sum, 10, 5) // результат: 15
Как работают SAM-conversions?
Single Abstract Method (SAM) интерфейсы — это интерфейсы только с одним абстрактным методом (функциональные интерфейсы). Kotlin поддерживает соглашение SAM — автоматическую конвертацию функций и lambda между Kotlin и Java.
SAM-conversions позволяют использовать Java-интерфейсы с единственным абстрактным методом в Kotlin, как если бы это были функциональные типы. В Kotlin вы можете использовать такие интерфейсы для создания лямбда-выражений без явного определения функционального типа.
При использовании интерфейса с единственным абстрактным методом в качестве функционального интерфейса в Java, вы можете передавать его экземпляры вместо лямбда-выражений. Это тоже возможно в Kotlin, но на самом деле Kotlin предоставляет более простой синтаксис для этого. Когда вам нужно использовать функциональный интерфейс в Kotlin, вы можете передать lambda-выражение, которое соответствует сигнатуре единственного метода интерфейса, вместо экземпляра интерфейса. Компилятор сам преобразует лямбда-выражение в экземпляр интерфейса, используя функцию-расширение метода invoke интерфейса. Пример:
Single Abstract Method (SAM) интерфейсы — это интерфейсы только с одним абстрактным методом (функциональные интерфейсы). Kotlin поддерживает соглашение SAM — автоматическую конвертацию функций и lambda между Kotlin и Java.
SAM-conversions позволяют использовать Java-интерфейсы с единственным абстрактным методом в Kotlin, как если бы это были функциональные типы. В Kotlin вы можете использовать такие интерфейсы для создания лямбда-выражений без явного определения функционального типа.
При использовании интерфейса с единственным абстрактным методом в качестве функционального интерфейса в Java, вы можете передавать его экземпляры вместо лямбда-выражений. Это тоже возможно в Kotlin, но на самом деле Kotlin предоставляет более простой синтаксис для этого. Когда вам нужно использовать функциональный интерфейс в Kotlin, вы можете передать lambda-выражение, которое соответствует сигнатуре единственного метода интерфейса, вместо экземпляра интерфейса. Компилятор сам преобразует лямбда-выражение в экземпляр интерфейса, используя функцию-расширение метода invoke интерфейса. Пример:
interface OnClickListener {
fun onClick(view: View)
}
class Button {
fun setOnClickListener(listener: OnClickListener) {
// ...
}
}
val button = Button()
button.setOnClickListener { view ->
// обработка нажатия кнопки
}
В этом примере мы определяем интерфейс OnClickListener с единственным абстрактным методом onClick. Затем мы создаем класс Button, который может иметь слушатель, реализующий данный интерфейс. После этого мы создаем экземпляр Button и передаем лямбда-выражение с соответствующей сигнатурой в качестве слушателя. Компилятор автоматически преобразует это лямбда-выражение в экземпляр интерфейса OnClickListener, используя функцию-расширение invoke интерфейса.Koin: Простой и легковесный фреймворк для внедрения зависимостей
Принцип внедрения зависимостей становится все более неотъемлемой частью процесса разработки. Без него сложно представить себе достижение желанного разделения обязанностей в коде или обеспечение должного уровня тестируемости.
В то же время, хотя Spring Framework и является широко распространенным выбором, он далеко не всем подходит. Некоторым было бы предпочтительнее использовать более простые и легковесные фреймворки с продвинутой поддержкой асинхронных операций ввода-вывода. Другие были бы признательны за статическое разрешение зависимостей для более быстрого запуска приложения.
Читать статью
Принцип внедрения зависимостей становится все более неотъемлемой частью процесса разработки. Без него сложно представить себе достижение желанного разделения обязанностей в коде или обеспечение должного уровня тестируемости.
В то же время, хотя Spring Framework и является широко распространенным выбором, он далеко не всем подходит. Некоторым было бы предпочтительнее использовать более простые и легковесные фреймворки с продвинутой поддержкой асинхронных операций ввода-вывода. Другие были бы признательны за статическое разрешение зависимостей для более быстрого запуска приложения.
Читать статью
Teletype
Koin: Простой и легковесный фреймворк для внедрения зависимостей
Принцип внедрения (инжектирования) зависимостей становится все более неотъемлемой частью процесса разработки. Без него сложно...
Указатели на функции (Function references, Bound callable references)
В языке Kotlin есть возможность работать с функциями как с объектами. Функции можно сохранять в переменные, передавать как аргументы и возвращать из других функций. Для этого можно использовать функциональные ссылки (Function references), которые представляют собой указатель на функцию.
1. Function references
Синтаксис функциональной ссылки имеет следующий вид:
Bound callable references (привязанные ссылки) — это то же самое понятие, что и указатели на методы, но в случае, когда метод вызывается на экземпляре класса. В этом варианте мы можем использовать ссылку на метод, связанную с конкретным экземпляром класса. Для создания привязанной ссылки на метод используется следующий синтаксис: <object_name>::<method_name>.
Допустим, что у нас есть экземпляр класса person типа Person. Тогда мы можем использовать ссылку на метод getName() для получения его имени:
В языке Kotlin есть возможность работать с функциями как с объектами. Функции можно сохранять в переменные, передавать как аргументы и возвращать из других функций. Для этого можно использовать функциональные ссылки (Function references), которые представляют собой указатель на функцию.
1. Function references
Синтаксис функциональной ссылки имеет следующий вид:
::function_name. Указатели на функции представляют собой сокращенную форму записи вызова функции. Вместо того, чтобы объявлять лямбда-выражение и передавать его как аргумент функции, можно использовать ссылку на существующий метод. Например, у нас есть класс Person с методом getName():class Person(val name: String) {
fun getName(): String = name
}
Тогда мы можем использовать указатель на метод getName() вместо лямбда-выражения:val persons = listOf(Person("Alice"), Person("Bob"))
val names = persons.map(Person::getName)
2. Bound callable referencesBound callable references (привязанные ссылки) — это то же самое понятие, что и указатели на методы, но в случае, когда метод вызывается на экземпляре класса. В этом варианте мы можем использовать ссылку на метод, связанную с конкретным экземпляром класса. Для создания привязанной ссылки на метод используется следующий синтаксис: <object_name>::<method_name>.
Допустим, что у нас есть экземпляр класса person типа Person. Тогда мы можем использовать ссылку на метод getName() для получения его имени:
val person = Person("Alice")
val name = person::getName
Здесь name будет ссылаться на метод getName() объекта person.Задачи про PEG-парсеры
Когда-то я хотел сделать контест по парсингу для Codeforces. Придумал задания двух типов:
1. Дается неформальное описание языка, по которому нужно создать грамматику (например, "язык с правильными скобочными последовательностями")
2. Даны примеры строк в языке, по которым нужно восстановить грамматику
У обоих типов заданий есть свои проблемы, так что контест я не сделал.
В итоге я сделал игру программу, в которой можно решать задания второго типа, при этом проверять строки на принадлежность угадываемому языку.
Читать статью
Когда-то я хотел сделать контест по парсингу для Codeforces. Придумал задания двух типов:
1. Дается неформальное описание языка, по которому нужно создать грамматику (например, "язык с правильными скобочными последовательностями")
2. Даны примеры строк в языке, по которым нужно восстановить грамматику
У обоих типов заданий есть свои проблемы, так что контест я не сделал.
В итоге я сделал игру программу, в которой можно решать задания второго типа, при этом проверять строки на принадлежность угадываемому языку.
Читать статью
Teletype
Задачи про PEG-парсеры
Когда-то я хотел сделать контест по парсингу для Codeforces. Придумал задания двух типов:
Что такое inline функции, в чем их преимущество?
В Kotlin есть два типа функций: обычные и встроенные. Обычные функции похожи на функции в других языках программирования. Но встроенные функции имеют модификатор inline. Это позволяет компилятору подставить тело функции прямо в место её вызова.
Как работают inline функции?
Использование анонимных функций (лямбда-выражений) в Kotlin приводит к дополнительным затратам памяти. При использовании лямбда-выражения создается объект FunctionN (где N — количество параметров в лямбда-выражении), который содержит ссылку на само лямбда-выражение и может содержать захваченные переменные. При передаче лямбда-выражения в качестве параметра метода также создается новый объект FunctionN, что приводит к дополнительным затратам памяти.
Поэтому, чтобы избежать создания дополнительных объектов при передаче лямбда-выражений в функцию в качестве параметра, можно использовать встраивание (inline). Ключевое слово inline позволяет компилятору подставить тело функции непосредственно в место её вызова, вместо того, чтобы создавать объекты функций. Таким образом можно уменьшить затраты на создание объектов и улучшить производительность приложения.
Пример синтаксиса inline-функций с лямбдой:
В Kotlin есть два типа функций: обычные и встроенные. Обычные функции похожи на функции в других языках программирования. Но встроенные функции имеют модификатор inline. Это позволяет компилятору подставить тело функции прямо в место её вызова.
Как работают inline функции?
Использование анонимных функций (лямбда-выражений) в Kotlin приводит к дополнительным затратам памяти. При использовании лямбда-выражения создается объект FunctionN (где N — количество параметров в лямбда-выражении), который содержит ссылку на само лямбда-выражение и может содержать захваченные переменные. При передаче лямбда-выражения в качестве параметра метода также создается новый объект FunctionN, что приводит к дополнительным затратам памяти.
Поэтому, чтобы избежать создания дополнительных объектов при передаче лямбда-выражений в функцию в качестве параметра, можно использовать встраивание (inline). Ключевое слово inline позволяет компилятору подставить тело функции непосредственно в место её вызова, вместо того, чтобы создавать объекты функций. Таким образом можно уменьшить затраты на создание объектов и улучшить производительность приложения.
Пример синтаксиса inline-функций с лямбдой:
inline fun functionName(parameter1: Type1, parameter2: Type2, ..., parameterN: TypeN, block: () -> Unit): ReturnType {
// function body
}
Модификатор inline влияет и на функцию, и на лямбду, переданную ей: они обе будут встроены в место вызова.Ускоряем поиск по коду в Android Studio
Рассмотрим возможности Android Studio, позволяющие быстрее ориентироваться в коде: находить нужные фрагменты и выявлять связи между ними.
Если вы опытный пользователь, то вам известно большинство нижеперечисленных лайфхаков. Но я узнавал о многих возможностях случайно, через многие месяцы работы в Android Studio, поэтому хочу рассказать всё, везде и сразу.
Читать статью
Рассмотрим возможности Android Studio, позволяющие быстрее ориентироваться в коде: находить нужные фрагменты и выявлять связи между ними.
Если вы опытный пользователь, то вам известно большинство нижеперечисленных лайфхаков. Но я узнавал о многих возможностях случайно, через многие месяцы работы в Android Studio, поэтому хочу рассказать всё, везде и сразу.
Читать статью
Teletype
Ускоряем поиск по коду в Android Studio
Рассмотрим возможности Android Studio, позволяющие быстрее ориентироваться в коде: находить нужные фрагменты и выявлять связи между ними.