Русский
Русский
English
Статистика
Реклама

Обобщенное программирование

Recovery mode Разбираем классы по косточкам или интроспектируем типы в Typescript

03.01.2021 02:10:08 | Автор: admin


Крутую ты штуку придумал, Стёпа, сообщил мне коллега, осознав рассказанную ему идею. Надеюсь это действительно так, хоть и не скажу, что в том, о чём далее пойдёт речь, есть что-то безумно новаторское, однако, на мой взгляд, интерес данный материал всё же представляет.
Сегодня поговорим о применении интроспекции в разработке веб-интерфейсов, немного пошаманим с обобщённым программированием и изобретём велосипед в Typescript, имеющий похожий аналог в .NET.


Что мы знаем об интроспекции?


Википедия гласит, что это возможность запросить тип и структуру объекта во время выполнения программы.


Ну то есть имеется класс:


class Person {    height: number;    weight: number;    bloodPressure: string;}

Его объект определяется набором полей, каждое из которых имеет, по крайней мере, свой тип и значение.



При этом данный массив мы можем получить в любой момент выполнения программы, вызвав какую-то функцию.


const fields = ObjectFields.of(Person)

От теории к практике


Я, конечно, человек с замыленными мозгами, но в данной ситуации буду мыслить шаблонно. Вытянуть имена полей можно с помощью Object.keys, а типизировать это дело уже через keyof. Далее используя ключи, как индексы, получаем значения и данные о них.
Пропустив через себя эту информацию, можно выразить свои выводы следующим образом. Начнём с простого, описав некий тип, характеризующий поле объекта.


interface IObjectField<T extends object> {    readonly field: keyof T;    readonly type: string;    readonly value: any;}

Если задуматься, то можно увидеть, что это сильно напоминает FieldInfo. Правда я это понял в момент написания статьи :)
И сейчас самое время вспомнить, что Typescript это не .NET. Например, создавать экземпляры объекта в контексте обобщённого программирования здесь можно только с помощью фабрик. То есть, как в C# не прокатит.
Если описывать конструктор некого класса, то получится приблизительно следующее.


interface IConstructor<T> {    new(...args: any[]): T;}

Хорошо, попробуем создать инструмент для интроспекции класса, который бы удовлетворял следующим требованиям:


  1. Всё, что у нас есть на входе это конструктор изучаемого класса.
  2. На выходе мы получаем массив объектов типа IObjectField
  3. Сгенерированные данные неизменяемы.

Вот теперь рассуждения в начале раздела переведены на язык Typescript.


class ObjectFields<T extends object> extends Array<IObjectField<T>> {    readonly [n: number]: IObjectField<T>;    constructor(type: IConstructor<T>) {        const instance: T = new type();        const fields: Array<IObjectField<T>> = (Object.keys(instance) as Array<keyof T>)            .map(x => {                const valueType = typeof instance[x];                let result: IObjectField<T> = {                    field: x,                    type: valueType === 'object'                        ? (instance[x] as unknown as object).constructor.name                        : valueType,                    value: instance[x]                }                return result;            });        super(...fields);    }}

Попробуем "прочитать" класс Person и выведем данные на экран.


const fields = new ObjectFields(Person);console.log(fields);

Правда, вместо ожидаемого вывода получили пустой массив.



Как же так? Всё скомпилировалось и отработало без ошибок. Однако дело в том, что результирующий массив строится с помощью Object.keys, и поскольку в рантайме работает Javascript, то какой объект засунем, такой набор ключей и получим. А объект пустой, вот и информация о типах, которую мы попытались извлечь, куда-то потерялась. Чтобы её "вернуть", необходимо инициализировать поля класса какими-то начальными значениями.


class Person {    height: number = 80;    weight: number = 188;    bloodPressure: string = '120-130 / 80-85';}

Вуаля получили, что хотели.



Также протестируем более сложную ситуацию.


class Material {    name = "wood";}class MyTableClass {    id = 1;    title = "";    isDeleted = false;    createdAt = new Date();    material = new Material();}

Результат превзошёл ожидания.



И что с этим делать?


Первое, что пришло в голову: CRUD приложения на react теперь можно писать, реализуя обобщённые компоненты. Например, нужно сделать форму для вставки в таблицу. Пожалуйста, никто не запрещает делать что-то такое.


interface ITypedFormProps<T extends object> {    type: IConstructor<T>;}function TypedForm<T extends object>(props: ITypedFormProps<T>) {    return (        <form>            {new ObjectFields(props.type).map(f => mapFieldToInput(f))}        </form>    );}

И использовать потом этот компонент вот так.


<TypedForm    type={Person} />

Ну и саму таблицу сделать по такому же принципу тоже возможно.


Подводя итоги


Хочется сказать, что штука получилась интересная, но пока непонятно, что с ней делать дальше. Если вам было интересно или есть какие-либо предложения, пишите в комментариях, а пока до новых встреч! Спасибо за внимание!

Подробнее..

Шаблоны и концепты в С20

15.04.2021 14:13:15 | Автор: admin

Привет, Хабр!

Недавно Егор Суворов, преподаватель курса по С++ в Питерской Вышке, прочитал лекцию о некоторых особенностях языка для участников Всероссийской олимпиады школьников по информатике. Егор рассказал о шаблонах в C++, а также где и зачем они возникают: обобщённое программирование структур данных и алгоритмов, функторы и лямбда-функции, как можно повысить уровень абстракций и упростить код.

Важное уточнение: эта лекция не попытка объять необъятное, а краткий экскурс по полезным возможностям C++ для членов олимпиадного сообщества: от извлечения кода в класс до внутренних механизмов работы лямбда-функций и щепотки ограничений (constraints) из C++20. Если интересно, приглашаем к просмотру.

Подробные таймкоды

00:53 Что нужно знать перед просмотром лекции

02:00 Особенности С++

03:10 Хорошие источники знаний и практик в C++

04:45 Классы. Стек с минимумом

06:21 Создание своей структуры

09:03 Запрещаем прямой доступ

09:53 Упрощаем отладку

10:29 Шаблоны классов

11:24 Статический полиморфизм в разных языках

12:03 Оптимизация

12:27 Ошибки компиляции и инстанцирование

13:40 Ограничения (С++20)

15:01 Шаблоны функций

15:27 Автовывод параметров

16:21 Class Template Argument Deduction (CTAD, С++17)

16:56 Ошибки компиляции и инстанцирование

17:47 Обобщенное программирование

19:12 Вложенные типы

20:10 Продвинутые техники

20:33 Функторы

21:00 Функциональные объекты

21:56 Как параметр шаблона

22:30 Функторы с состоянием

23:26 Функторы с состоянием для контейнеров

24:42 Лямбда-выражения

25:38 Расшифровка лямбды

26:28 Сохранение в переменную

27:27 Рекурсия не поддерживается

27:56 Захваты по значению и ссылке

29:18 Захват с инициализатором

30:29 Комбинированные захваты

31:16 Применение функторов

32:15 IIFE

33:18 Вектор лямбд и стирание типов (type erasure)

34:36 Функтор как параметр функции

35:51 Функтор как поле класса

37:45 Более сложные структуры данных (декартово дерево, дерево отрезков)

38:34 За кадром: лямбды-компараторы

39:48 За кадром: более сложные шаблоны

41:23 Студенческие проекты на C++ (в прошлом году рассказывали о проектах наших первокурсниках)

Если у вас остались вопросы, смело задавайте их в комментариях или лично Егору.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru