В Rust рассмотрите возможность указания аргумента типа в вызове функции: `::<T>`

Я просто хочу вызвать эту функцию из imageproc ящика. Прямо сейчас я делаю это так:

let mut contours = find_contours_with_threshold(&src_image.to_luma8(), 10);

И я продолжаю получать эту ошибку:

error[E0283]: type annotations needed
  --> src/main.rs:77:24
   |
77 |     let mut contours = find_contours_with_threshold(&src_image.to_luma8(), 10);
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `find_contours_with_threshold`
   |
   = note: cannot satisfy `_: Num`
note: required by a bound in `find_contours_with_threshold`
  --> /home/mike/.cargo/registry/src/github.com-1ecc6299db9ec823/imageproc-0.23.0/src/contours.rs:61:8
   |
61 |     T: Num + NumCast + Copy + PartialEq + Eq,
   |        ^^^ required by this bound in `find_contours_with_threshold`
help: consider specifying the type argument in the function call
   |
77 |     let mut contours = find_contours_with_threshold::<T>(&src_image.to_luma8(), 10);
   |                                                    +++++

Я понимаю, что ржавчина не может понять, чего ожидать в результате вызова этой функции. В документации он должен возвращать Vec<Contour<T>>, где T: Num + NumCast + Copy + PartialEq + Eq, но я не знаю, как перенести это в свой код.

Я пытался сделать это следующим образом: let mut contours: Vec<Contour<dyn Num + NumCast + Copy + PartialEq + Eq>> = find_contours_with_threshold(&src_image.to_luma8(), 10); но я до сих пор не понимаю, что делаю, поэтому любая помощь будет отличной.

Это что-то вроде слишком большого количества значений для распаковки в python? я должен был сделать что-то вроде let x, y, z = find_contours..()?

Что произойдет, если вы используете let mut contours = find_contours_with_threshold::<i32>(&src_image.to_luma8(), 10); (или другой подходящий целочисленный тип)? Это работает? Я не знаком с этой библиотекой, но она запрашивает конкретный тип для вставки Contour без ограничений.

Kevin Anderson 21.11.2022 17:12

@KevinAnderson это действительно работает. Спасибо! Разве этот конкретный тип не должен быть из Num, NumCast, Copy, PartialEq, Eq?

Mike 21.11.2022 17:24

@Майк Num, NumCast, Copy, ... это черты. Граница T: Num + NumCast + ... означает, что тип T должен иметь реализацию этих свойств. Один тип, удовлетворяющий такому ограничению, — это i32, однако он не единственный. Сообщение компилятора означает, что он не может определить, какой тип вам нужен.

jthulhu 21.11.2022 18:13
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
3
118
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Существует параметр типа T, который имеет некоторые границы характеристик (Num, NumCast и т. д.), и он не ограничен.

Конечно, это может быть i32, но вы также можете определить собственный тип:

#[derive(Copy, Clone)]
struct MySillyNumber;

impl Num for MySillyNumber {}

// the rest of the required traits

и это такой же действительный тип для T, как и i32.

Вам нужно сообщить rustc, что такое T. Вы можете сделать это несколькими способами:

  • турбофиш: find_contours_with_threshold::<i32>()
  • явное описание типа: let x: Vec<Contour<i32>> = find_contours_with_threshold()
  • передать его функции:
fn main() {
  let x = find_contours_with_threshold();
  foo(x);
}

fn foo(x: Vec<Contour<i32>>) {}
  • или любым другим способом, который дает rustc конкретный тип для замены T.

Обратите внимание, что это отличается от использования Vec<Contour<dyn Num + ...>>. Это превратит элементы в «объекты признаков», которые используют динамическую отправку (с виртуальной таблицей) для выполнения полиморфизма во время выполнения. Это, вероятно, не то, что вам нужно, в значительной степени потому, что dyn Trait не имеет известного размера, а это означает, что он не может появиться в стеке без использования какого-либо указателя. И хотя Vec, возможно, является интеллектуальным указателем, он требует, чтобы содержимое имело фиксированный размер, поскольку он полагается на это для индексации.

Спасибо @cameron1024 - Вы сформулировали это как ответ и с гораздо большей уверенностью, чем я в своем комментарии. Я ценю, как вы расширили различные типичные способы его указания. Для людей, пришедших с C++ (т.е. для меня), добавление типа шаблона к возвращаемому значению является распространенным шаблоном в Rust, но для меня это действительно странно, поскольку правила перегрузки функций C++ означают «да» для аргументов, но не для возвращаемых типов. Не то же самое, что конструкции, перегрузки и шаблоны, но тем не менее, мой мозг работает по умолчанию, поэтому такие вещи меня немного сбивают с толку.

Kevin Anderson 21.11.2022 19:07

ИМО, вывод типов в Rust на самом деле является чем-то вроде пушки для людей, плохо знакомых с языком. Не очевидно, почему что-то работает в одном фрагменте, а не в другом, и это может быть из-за единственного вызова функции на 100 строк ниже, которая обеспечивает конкретный тип. Без него язык был бы непригоден для использования, но он обеспечивает форму «действия на расстоянии», что наверняка может сбивать с толку.

cameron1024 23.11.2022 07:26

Другие вопросы по теме