LINUX.ORG.RU

Функция, принимающая любую последовательность?

 , ,


2

6

Пытаюсь на расте написать аналог такого:

def print_items(items):
    for item in items:
        print item

Это же просто, да?

Растишкин код:

// так работает
fn print_items(items: &[&str]) {
    for item in items {
        println!("{}", item);
    }
}

// а так не работает, блджад!
fn print_items_iter<'a, I> (items: I)
    where I: IntoIterator<Item = &'a str>
{
    for item in items {
        println!("{}", item);
    }
}

fn main() {
    let items = ["pracuj", "kurwo"];
    print_items(&items);
    print_items_iter(&items);
}

Не компилится:

src/main.rs:21:5: 21:21 error: type mismatch resolving `<&[&str; 2] as core::iter::IntoIterator>::Item == &str`:
 expected &-ptr,
    found str [E0271]
src/main.rs:21     print_items_iter(&items);
                   ^~~~~~~~~~~~~~~~
src/main.rs:21:5: 21:21 help: run `rustc --explain E0271` to see a detailed explanation
src/main.rs:21:5: 21:21 note: required by `print_items_iter`

Штоааа? В доке же написано, что слайсы реализуют IntoIterator. Чего он от меня хочет? Алсо, &[&str; 2] - это таки слайс или ссылка на массив? Почему? Я уже совсем ничего нипа

Растишка: формула здорового росту.



Последнее исправление: HeipaVai1o (всего исправлений: 2)

А вообще нужно так:

fn print_items_iter<'a, I: IntoIterator> (items: I)
    where I::Item: std::fmt::Display
{
    for item in items {
        println!("{}", item);
    }
}

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

where I: IntoIterator<Item = &'a &'a str>

Лол, и правда ведь. Ну и вещества. Интересно, какой код из этого сгенерится - так и будет браться указатель на указатель, а потом разыменовываться?

А вообще нужно так:
where I::Item: std::fmt::Display

Да это просто пример был, в настоящем коде со строками другое делается.

HeipaVai1o
() автор топика

&[&str; 2] - это таки слайс или ссылка на массив?

Это ссылка на массив. Которая decay-ится в &[&str], т. е. слайс из &str. А IntoIterator для слайса из T возвращает &T, т. е. &&str.

intelfx ★★★★★
()
Ответ на: комментарий от HeipaVai1o

Вполне вероятно. Там все оптимизации делаются на этапе LLVM IR. Разумеется, да. У тебя массив указателей на строку. Очевидно, итератор по такому массиву — это указатель на указатель. Даже из плюсовой семантики это очевидно.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 2)

fn print_items_iter<'a, I> (items: I) where I: IntoIterator<Item = &'a str>

Черт, аж волосы на жопе дыбом встали.

anonymous
()
Ответ на: комментарий от intelfx

Очевидно, итератор по такому массиву — это указатель на указатель. Даже из плюсовой семантики это очевидно.

Да, действительно. Спасибо, слегка прояснилось.

HeipaVai1o
() автор топика
Ответ на: комментарий от buddhist

Энжой ёр перл голф. Новый крутой язык для обмена мозголомными сниппетами.

anonymous
()
Ответ на: комментарий от intelfx

Я прошу прощения, можно задать праздный вопросец. А если у нас там не строки, а строки или числа? То как тогда будет?

den73 ★★★★★
()
Ответ на: комментарий от den73

Или не знаю, как там называются угловые скобки.

den73 ★★★★★
()
Ответ на: комментарий от den73

Явное указание лайфтайма забыл убрать. А насчёт угловых скобок — в расте наследование интерфейсов и шаблонные функции объединены в некоторую общую концепцию.

intelfx ★★★★★
()
Ответ на: комментарий от den73

Т. е. интерфейс в расте называется трейтом, и в заголовке той функции сказано что-то вроде «функция от T, где T — любой тип, удовлетворяющий трейту (интерфейсу) fmt::Display».

При этом раст по возможности делает static dispatch, т. е. раскрывает функцию подобно шаблонной в плюсах. А можно передавать в функцию ссылку на трейт (fn foo(x: &std::fmt::Display)), тогда будет dynamic dispatch (т. е. виртуальный вызов).

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

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 2)
Ответ на: комментарий от intelfx

сказано что-то вроде

Да мне кажется вся суть в том, что сказано не оно. Что сказано, я не понимаю, вроде как итератор с каким-то доп. ограничением на тип того, по чему он итерирует. Т.е. IntoIterator - это, я так понял, не что-то конкретное, а некое семейство типов (или трейтов, или не знаю чего). Но в написании слова IntoIterator это никак не видно. В плюсах были бы за ним угловые скобки и так было бы ясно, что это не просто тип. Наверное, мне именно это не нравится. Также мне не нравится where - текст не читается слева направо, а значит, его читать сложнее. Хотя если тебе нравятся плюсы, тебя это не должно напрягать. Мне не нравится плюсы, и не нравятся они мне, наверное, во многом именно тем, что там текст не читается ни слева направо, ни справа налево, а представляет из себя клубок, в котором нужно найти кончик и за него тянуть.

Ну впрочем всё равно спасибо за ответы.

den73 ★★★★★
()
Ответ на: комментарий от den73

Также мне не нравится where - текст не читается слева направо

Хм... а как же он читается? Ведь where просто уточняет ограничения типов и появляется оно после их обьявления, то есть мы всё-таки читаем слева направо (и сверху вниз).

Хотя мне where тоже не нравится, но скорее из-за дублирования.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Хм... а как же он читается?

А так: нашёл слово, потом ищи дальше где для него where. Потом вернись и читай дальше от этого слова направо. Иначе у тебя за спиной непонятность осталась.

den73 ★★★★★
()
Ответ на: комментарий от anonymous

Для коротких объявлений, но для длинных where удобнее.

А typedef там есть? Вот его надо для длинных бы.

den73 ★★★★★
()
Ответ на: комментарий от anonymous

Но я имел ввиду большое кол-во типов|требований в описании.

Думается, мы имели в виду одно и то же.

den73 ★★★★★
()
Ответ на: комментарий от den73

А так: нашёл слово, потом ищи дальше где для него where. Потом вернись и читай дальше от этого слова направо.

Ну это спорный вопрос. Можно трактовать как последующее уточнение: тип I реализующий IntoIterator, у которого Item реализует Display. В хаскеле вон where любят, вроде. Хотя и делает оно другое, но принцип похожий - «нюансы» проясняются позже.

DarkEld3r ★★★★★
()
Ответ на: комментарий от den73

Думается, мы имели в виду одно и то же.

Нет.

fn qwertyuiop<A: SomeTrait + SomeTrait + SomeTrait + ...,
              B: SomeTrait + SomeTrait + SomeTrait + ...,
              C: SomeTrait + SomeTrait + SomeTrait + ...,
              D: SomeTrait + SomeTrait + SomeTrait + ...,
              E: SomeTrait + SomeTrait + SomeTrait + ...,
              ...>
              (a: A, b: B, c: C, d: D, e: E, ...) {
    ...
}

fn qwertyuiop<A, B, C, D, E, ...>(a: A, b: B, c: C, d: D, e: E, ...)
    where A: SomeTrait + SomeTrait + SomeTrait + ...,
          B: SomeTrait + SomeTrait + SomeTrait + ...,
          C: SomeTrait + SomeTrait + SomeTrait + ...,
          D: SomeTrait + SomeTrait + SomeTrait + ...,
          E: SomeTrait + SomeTrait + SomeTrait + ...,
          ...
{
    ...
}
anonymous
()
Ответ на: комментарий от intelfx

Кстати, а почему нельзя так?

Тоже интересно... «Можно» через равно, но тогда смысл другой получится: элемент не реализует трейт, а является им.

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

where A: SomeTrait + SomeTrait + SomeTrait + ...

что мешает это вынести вовне определения функции и сделать псевдонимом типа или как оно там называется? Ведь оно же наверняка понадобится и в какой-нибудь соседней функции тоже?

den73 ★★★★★
()
Ответ на: комментарий от den73

Да мне кажется вся суть в том, что сказано не оно.

Тебе кажется.

В плюсах были бы за ним угловые скобки

Нет. Трейт - это что-то вроде интерфейса из жабы или чисто абстрактного класса из крестов. Угловые скобки не имеют отношения к интерфейсам от слова «совсем». Отличие растовских интерфейсов от крестовых и жавовских только в том, что на их базе можно делать как dynamic, так и static dispatch.

anonymous
()
Ответ на: комментарий от den73

что мешает это вынести вовне определения функции и сделать псевдонимом типа

То, что это не тип, а куча трейтов.

anonymous
()
Ответ на: комментарий от intelfx

Кстати, а почему нельзя так?

Чтоб синтаксис не усложнять. Сейчас там что-то вроде <идентификатор: трейт{, идентификатор: трейт}> (опустим лайфтаймы для простоты), а у тебя для такого трейта, инстанциируемого трейтом, придётся вводить новую сущность. Твоё предложение, конечно, удобное и интуитивное, но вот так утяжелять синтаксис языка явно не стоит, тем более на данном этапе его развития.

anonymous
()
Ответ на: комментарий от intelfx

Аноним-растолюб

И да, я не растолюб, я просто интересующийся мимопроходил. И у меня опыт сношения с самыми разными языками, из коих раст немало позаимствовал.

anonymous
()
Ответ на: комментарий от anonymous

<идентификатор: трейт{, идентификатор: трейт}>

Так ведь

fn print<I: IntoIterator<Item = SomeType>>(items: I)

вот так можно же. А с двоеточием и трейтом нельзя.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от anonymous

Чтоб синтаксис не усложнять.

В голосину!

anonymous
()
Ответ на: комментарий от intelfx

I: IntoIterator<Item = SomeType>

вот так можно же.

Потому что IntoIterator<Item=SomeType> - это трейт, точнее, специализация обобщённого трейта. Его можно юзать, например, в объявлении переменных. А IntoIterator<Item: SomeTrait> - это сахарок, который кроме объявления шаблонов больше нигде не будет использоваться. Ортогональность? Не, не слышали. Нет, конечно, сахарок тоже бывает нужен, но авторам раста сейчас надо фичами языка заниматься, а потом уже о сахарке думать.

anonymous
()
Ответ на: комментарий от den73

Смотри не лопни от важности

Не лопну. Я просто намекал, что твои вкусы в ЯП слишком необычны, чтобы их удовлетворил статически-типизированный ЯП.

На лиспе пишу сейчас и раньше тоже.

Динамическая типизация? Там тоже свои недостатки.

anonymous
()
Ответ на: комментарий от den73

Если нельзя, то я думаю, что это дефект.

Не уверен. Всё-таки «любой тип реализующий список трейтов» в отрыве от контекста не так уж сильно полезен. Можно, конечно, придумать случаи, но чаще такиm типам будет логично разные имена раздать в зависимости от контекста.

Опять же, разве это не усложнит чтение кода? Видишь функцию, видишь какой-то тип и надо ещё искать что он из себя представляет.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Опять же, разве это не усложнит чтение кода? Видишь функцию, видишь какой-то тип и надо ещё искать что он из себя представляет.

Давай тогда откажемся от функций, структур и прочих способов сокращения кода. А то ведь видишь в коде функцию или структуру и нужно лезть в исходник и смотреть, что делает функция и какие поля в структуре.

den73 ★★★★★
()
Ответ на: комментарий от anonymous

Я просто намекал, что твои вкусы в ЯП слишком необычны

Мои вкусы просты: если что-то много раз повторяется, то должен быть способ сокращённой записи этого.

den73 ★★★★★
()
Ответ на: комментарий от den73

А то ведь видишь в коде функцию или структуру и нужно лезть в исходник и смотреть, что делает функция и какие поля в структуре.

Ну а так мы получим на одно действие больше, а профит сомнителен. Впрочем, основной аргумент у меня был другим, а за «чтение слева направо» ты ратовал.

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.