
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.30] |
![]() |
|
Страницы: (33) « Первая ... 4 5 [6] 7 8 ... 32 33 ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#76
,
|
|
![]() |
Сообщ.
#77
,
|
|
|
Цитата Qraizer @ ![]() А, понял откуда вы определения берёте. За сим закончим. |
Сообщ.
#78
,
|
|
|
Цитата MyNameIsIgor @ Эм. Короткий пример можно?ООП-интерфейсы не единственный способ (по крайней мере в плюсах) обеспечения динамической диспетчеризации. В C++ мутабельности/иммутабельности как таковой нет, но есть константность, которой иногда можно заменить иммутабельность. Константость задается вполне себе на уровне типа. И можно создать шаблонную функцию принимающую как константный, так и мутабельный тип. |
Сообщ.
#79
,
|
|
|
Цитата applegame @ Короткий пример можно? Указатели на функции же. |
Сообщ.
#80
,
|
|
|
Цитата MyNameIsIgor @ А, точно. Часто встречается в сяшечных проектах. И часто как эмуляция тех самых ООП-интерфейсов Указатели на функции же. ![]() |
Сообщ.
#81
,
|
|
|
Неявно - никак. Но к типу можно предъявить требование наличия реализации трейта ToString. Цитата applegame @ Ну и вторая задача: без оберток создать массив в который можно было бы засунуть объект любого типа неявно кастующегося в строку. Правильно я понимаю, что в этом "массиве" будут лежать типы разного размера? Тогда нет, нельзя, можно сложить только указатели на такие типы. Неявно - нет. Наследование есть только для трейтов. У трейтов "нет размер", вернее он неизвестен. Как их хранить в массиве? Можно хранить ссылки/указатели. Цитата D_KEY @ Ну встроенные(несужающие) касты есть какие-то, да. Но свои сделать нельзя, если я правильно понимаю. Аналог reinterpret_cast тоже есть. Естественно, он объявлен как unsafe. А что значит "нельзя сделать свои касты"? Кто помешает, как и в С++ сделать функцию, например, my_super_cast? Можно и макрос. Добавлено Нет, только через "as" (ключевое слово): ![]() ![]() let e: i8 = 10; let ee: i32 = e; // error: mismatched types: expected `i32`, found `i8` let eee = e as i32; // OK. Добавлено В курсе, но я лучше подожду, пусть и С++17, а то и дальше, чем таким пользоваться. ![]() Нет. Почему? |
Сообщ.
#82
,
|
|
|
Цитата DarkEld3r @ В курсе, но я лучше подожду, пусть и С++17, а то и дальше, чем таким пользоваться. А мне вот нравится как asio ругается в случае чего. Правда, там по-своему сделано, не BCCL. |
Сообщ.
#83
,
|
|
|
Цитата DarkEld3r @ Пусть будут указатели, не суть.У трейтов "нет размер", вернее он неизвестен. Как их хранить в массиве? Можно хранить ссылки/указатели. Давайте попробуем выявить преимущества растовских трейтов перед D-шными интерфейсами/С++-ными абстрактными классами. Если таковые преимущества есть. Задача: Есть некий trait/интерфейс ToString описывающий функцию to_string без аргументов и возвращающую строку. Есть два произвольных типа Foo и Bar, нужно описать трейт ToString для этих типов. Создать эти трейты, и засунуть их в массив: Вариант на D. На C++ все аналогично: ![]() ![]() import std.stdio; import std.string; // это растовский trait interface ToString { string toString(); } // сторонний тип Foo struct Foo { int data; } // сторонний тип Bar struct Bar { long data; } // реализация traita ToString для стороннего типа Foo auto makeToString(Foo foo) { class Impl : ToString { Foo payload; override string toString() { return format("Foo(%s)", payload.data); } // конструктор this(Foo foo) { payload = foo; } } return new Impl(foo); } // реализация traita ToString для стороннего типа Bar auto makeToString(Bar bar) { class Impl : ToString { Bar payload; override string toString() { return format("Bar(%s)", payload.data); } // конструктор this(Bar bar) { payload = bar; } } return new Impl(bar); } void main() { ToString[] arr; auto bar = Bar(10); auto foo = Foo(20); arr ~= makeToString(bar); arr ~= makeToString(foo); foreach(o; arr) writeln(o.toString()); } |
Сообщ.
#84
,
|
|
|
Цитата Qraizer @ Потому что без них, как и интерфейсов, вполне себе живётся на аналогах. Интерфейс – абстрактный класс, имеющий только чистые методы и не имеющий полей, который наследуется всегда виртуально. Трейты вообще не нуждаются в отдельном описании, любой шаблон предъявляет требования к свойствам своих аргументов посредством выполняемых над ними операций. Стоп, не надо всё сразу. ![]() С терминологией я более-менее согласен, хотя и с оговорками. На мой взгляд, в С++ интерфейсы вполне есть, в том смысле, что их можно изображать абстрактными классами. Да, можно сказать, что у "у тру интерфейсов" есть больше ограничений и т.д. Но это, имхо, будет так же интересно как спорить, что такое интерфейсы - концепты или "интерфейсы". D-шные трейты вполне себе есть как отдельная сущность. И выглядят вполне удобно. А ведь они, по сути, как раз те же самые концепты, которые планируют появиться в С++. То есть с ними лучше, а значит "в отдельном описании" всё-таки нуждаются. Про концепты и "отлично показали" я говорил именно в контексте языка D. Который, в рамках "мейнстрима" не так уж далеко ушёл от раста и остаётся таким же "экспериментом". Добавлено Цитата MyNameIsIgor @ Конечно неправильно. Потому что интерфейсы в C++ - это концепты. Что непонятного? ![]() Как будет угодно, такой спор мне не интересен. Я и дальше продолжу называть абстрактные классы интерфейсами и пока что меня отлично понимали. ![]() Добавлено Цитата applegame @ В C++ мутабельности/иммутабельности как таковой нет, но есть константность В курсе, но я думаю, что мы друг друга поняли. Цитата applegame @ И можно создать шаблонную функцию принимающую как константный, так и мутабельный тип. А можно и не шаблонную. ![]() ![]() ![]() void f(const int&); Пожалуйста, передавать можно и константный и мутабельный тип. А вот когда нам надо принимать разные типы и разные действия выполнять, то уже начинаются приседания. И нужно оно, чаще всего, тупо для std::forward. У раста семантика перемещения работает немного иначе, да и перегрузки функций нет. Ну то есть, если есть конкретная задача - можем обсудить и посмотрим получится ли реализовать, а не просто "а вот можно в расте вот этакий шаблон изобратьзить?". Добавлено Цитата MyNameIsIgor @ А мне вот нравится как asio ругается в случае чего. Правда, там по-своему сделано, не BCCL. Ну если каждый будет свою реализацию велосипедить, то тоже не очень здорово. В общем, такие вещи лучше иметь в стандарте. |
Сообщ.
#85
,
|
|
|
Цитата Qraizer @ Нет. Задачу я описал чуть выше и решил с помощью создания дополнительных классов-оберток.Не понял. Задача написать метафункцию isConvertible<> на Плюсах? Я это делал, задолго до знакомства с бустом. И у Александреску есть. Цитата DarkEld3r @ Об этом я и говорю. Допустим у нас есть шаблонная функция принимающая ссылку и заполняющая ее объектом. Ссылка должна быть мутабельной. Вот немного притянутый за уши пример использования isMutable. вот когда нам надо принимать разные типы и разные действия выполнять, то уже начинаются приседания. |
Сообщ.
#86
,
|
|
|
Цитата DarkEld3r @ Как будет угодно, такой спор мне не интересен Сказал тот, кто сам предложил поспорить ![]() Цитата DarkEld3r @ Я и дальше продолжу называть абстрактные классы интерфейсами и пока что меня отлично понимали Жаль, что вы общаетесь лишь с теми, чем тесный мирок ограничен симулоподными взглядами. Созрел новый вопрос. Есть ли в Rust перегрузка обобщённых функций по трейтам? |
Сообщ.
#87
,
|
|
|
Цитата applegame @ Пусть будут указатели, не суть. Тогда никаких проблем: ![]() ![]() struct MyToStringVec { data: Vec<Box<ToString>> } struct Test; fn main() { let mut a = MyToStringVec { data: Vec::new() }; a.data.push(Box::new(10)); a.data.push(Box::new("test")); a.data.push(Box::new(Test)); // Error - Test не реализует ToString трейт } Цитата applegame @ Давайте попробуем выявить преимущества растовских трейтов перед D-шными интерфейсами/С++-ными абстрактными классами. Если таковые преимущества есть. Можно добавлять существующим типам реализацию нужныx трейтов. Наверное, всё, но опять же - трейты нужны, чуть ли не в первую очередь, для дженериков. Цитата applegame @ Есть некий trait/интерфейс ToString описывающий функцию to_string без аргументов и возвращающую строку. Есть два произвольных типа Foo и Bar, нужно описать трейт ToString для этих типов. Создать эти трейты, и засунуть их в массив: ![]() ![]() struct Foo { data: i32, } struct Bar { data: i64, } impl ToString for Foo { fn to_string(&self) -> String { format!("foo({})", self.data) } } impl ToString for Bar { fn to_string(&self) -> String { format!("bar({})", self.data) } } fn main() { let mut arr = Vec::<Box<ToString>>::new(); arr.push(Box::new(Foo { data: 10 })); arr.push(Box::new(Bar { data: 20 })); for val in arr { println!("{}", val.to_string()); } } Пожалуйста. Только я не пойму, что это должно доказать? Добавлено Цитата applegame @ Об этом я и говорю. Допустим у нас есть шаблонная функция принимающая ссылку и заполняющая ее объектом. Ссылка должна быть мутабельной. Вот немного притянутый за уши пример использования isMutable. Тогда почему функция не может быть такой? ![]() ![]() template <typename T> void f(T&) {} Цитата MyNameIsIgor @ Сказал тот, кто сам предложил поспорить ![]() Повторюсь - отвечал я другому человеку и на вполне конкретный комментарий. Как надо читать, чтобы начинать что-то доказывать про (пока ещё несуществующие, как языковый механизм) концепты я не знаю. Цитата MyNameIsIgor @ Жаль, что вы общаетесь лишь с теми, чем тесный мирок ограничен симулоподными взглядами. Ну спасибо, а то не знаю, что я бы без этой жалости делал. Действительно жаль, что я не начинаю рассказывать всё про все известные мне языки по любому поводу. Цитата MyNameIsIgor @ Созрел новый вопрос. Есть ли в Rust перегрузка обобщённых функций по трейтам? В смысле? У разных трейтов могут быть одноимённые функции (ну а иначе было бы очень странно). Но перегрузки функций, в целом, нет. Так что и иметь две одноимённые функции, которые отличаются только типом аргумента-трейта нельзя. Ну и специализации, в данный момент, тоже нет. Можно кидаться помидорами. ![]() |
Сообщ.
#88
,
|
|
|
Цитата DarkEld3r @ Это доказало, что никакой особой разницы между растовскими traitами и ООП-интерфейсами нет. Холивор не имеет смысла.Пожалуйста. Только я не пойму, что это должно доказать? Цитата DarkEld3r @ Наверное имеется в виду что-то типа:В смысле? ![]() ![]() void foo(T)(T data) if(isSerializable!T) {...} void foo(T)(T data) if(isStringConvertible!T) {...} |
Сообщ.
#89
,
|
|
|
Цитата applegame @ Это доказало, что никакой особой разницы между растовскими traitами и ООП-интерфейсами нет. Холивор не имеет смысла. Хм... если мы именно про "ООП интерфейсы", то их снаружи обычно расширять нельзя. В смысле, добавлять добавлять существующему типу наследование от интерфейса. Но я повторюсь про то, что трейты - они (ещё и) для дженериков. Ну и примеры всё-таки не эквивалентные. В D порождается новый тип, который наследуется от интерфейса и содержит данные. В расте - нет. Цитата applegame @ Наверное имеется в виду что-то типа: Тогда нет, нет перегрузки. Но в данном случае, проблемы не вижу - просто для типа реализуем трейт сериализации (внутри можно использовать конвертацию в строку). |
Сообщ.
#90
,
|
|
|
Цитата DarkEld3r @ Ну я же добавил. Де-факто тоже самое, просто на слегка более низком уровне.Хм... если мы именно про "ООП интерфейсы", то их снаружи обычно расширять нельзя. В смысле, добавлять добавлять существующему типу наследование от интерфейса. Цитата DarkEld3r @ Почему это нет? Твои реализации трейта ToString для Foo и Bar - это фактически порождение новых типов "унаследованных" от абстрактного трейта ToString и содержащих данные. В D порождается новый тип, который наследуется от интерфейса и содержит данные. В расте - нет. |