Как написать функции, которые принимают IntoIter в более общем плане - PullRequest
0 голосов
/ 23 июня 2019

Я читал ответ на вопрос stackoverflow и пытался изменить функцию history, чтобы она взяла IntoIter, где элемент может быть чем угодно, что может быть преобразовано в ссылку и имеет некоторые черты Debug в этом случае.

Если я удалю V: ?Sized из определения функции, компилятор ржавчины будет жаловаться, что во время компиляции он не знает размер str.

use std::fmt::Debug;

pub fn history<I: IntoIterator, V: ?Sized>(i: I) where I::Item: AsRef<V>, V: Debug {
    for s in i {
        println!("{:?}", s.as_ref());
    }
}

fn main() {
    history::<_, str>(&["st", "t", "u"]);
}

Я не понимаю, почему компиляторво-первых, показывает ошибку и не уверен, почему программа работает правильно, если я вроде чит с V: ?Sized.

1 Ответ

2 голосов
/ 24 июня 2019

Я вроде чит с V: ?Sized

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

В вашем случае, V доступен только по ссылке, поэтому он не обязательно должен быть Sized. Ослабление ограничения Sized делает вашу функцию максимально возможной, что позволяет использовать ее с большинством возможных типов.

Тип str не имеет размера, поэтому речь идет не только об обобщении, вам на самом деле нужно ослабить ограничение по умолчанию Sized, чтобы иметь возможность использовать вашу функцию с str.

...