Как получить Deref принуждение при использовании impl Trait - PullRequest
0 голосов
/ 28 января 2019

Эта функция возвращает первый элемент коллекции, подобной списку.Он работает для различных типов списков:

fn first<T: Copy>(x: impl Deref<Target=[T]>) -> T {
    x[0]
}

Например, он компилируется и запускается:

let data: Vec<usize> = vec![3, 4];
assert_eq!(first(data), 3);

let data: &[usize] = &[3, 4];
assert_eq!(first(data), 3);

let data: Rc<[usize]> = Rc::new([3, 4]);
assert_eq!(first(data), 3);

Также компилируется и запускается:

fn stub(x: &[usize]) -> usize {
    first(x)
}

let data: &[usize; 2] = &[3, 4];
assert_eq!(stub(data), 3);

assert_eq!(stub(&[3, 4]), 3);

Но это не скомпилируется:

let data: &[usize; 2] = &[3, 4];
assert_eq!(first(data), 3); // Fails.

assert_eq!(first(&[3, 4]), 3); // Fails.

Сообщение об ошибке:

type mismatch resolving `<&[usize; 2] as std::ops::Deref>::Target == [_]`

Мне кажется, я понимаю, что происходит.Для каждого типа T существует уникальный тип <T as Deref>::Target.Когда T равен &[usize; 2], целью является [usize; 2], а не [usize].Компилятор может привести &[T; 2] к &[T], если я его явно попросил, например, с помощью let или stub(), но если я этого не сделаю, он не сможет понять, что принудительное действие требуется.

Но это расстраивает.Для человека совершенно очевидно, для чего предназначены ошибочные вызовы, и компилятор понимает, что требуется для Vec<usize>, Box<[usize]>, Rc<[usize]>, &[usize] и т. Д., Поэтому не кажется бесполезным пытатьсячтобы он работал и для [usize; 2].

Вопрос: Есть ли удобный способ написать first(), чтобы последние два вызова тоже работали?Если нет, то есть ли синтаксис, чтобы попросить компилятор принудительно установить &[usize; 2] в &[usize], , то есть без использования let или stub()?

Детская площадка .

1 Ответ

0 голосов
/ 28 января 2019

Вы хотите использовать AsRef, а не Deref:

use std::rc::Rc;

fn first<T: Copy>(x: impl AsRef<[T]>) -> T {
    x.as_ref()[0]
}

fn main() {
    let data: Vec<usize> = vec![3, 4];
    assert_eq!(first(data), 3);

    let data: &[usize] = &[3, 4];
    assert_eq!(first(data), 3);

    let data: Rc<[usize]> = Rc::new([3, 4]);
    assert_eq!(first(data), 3);

    let data: &[usize; 2] = &[3, 4];
    assert_eq!(first(data), 3);
}
...