gpt4 book ai didi

generics - 如何为任何元素序列实现特征?

转载 作者:行者123 更新时间:2023-11-29 08:29:08 26 4
gpt4 key购买 nike

我正在尝试为任何元素序列实现一个特征,以便它适用于向量、数组和切片。到目前为止,我已经尝试了几种方法,但我无法编译其中任何一种:(

我有这个特征,一个使用它的函数,以及一个实现这个特征的基本数据类型:

trait Hitable {
fn hit(&self, val: f64) -> bool;
}

fn check_hit<T: Hitable>(world: &T) -> bool {
world.hit(1.0)
}

struct Obj(f64);

impl Hitable for Obj {
fn hit(&self, val: f64) -> bool {
self.0 > val
}
}

我希望能够为 Obj 的序列实现该特性。如果我将它限制为矢量,它会工作得很好:

impl<T> Hitable for Vec<T>
where
T: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.iter().any(|h| h.hit(val))
}
}

fn main() {
let v = vec![Obj(2.0), Obj(3.0)];
println!("{}", check_hit(&v));
}

但我想让它更通用,以便它适用于数组和切片;我该怎么做?

我尝试了以下四种尝试:

尝试 #1:针对 Hitables 上的迭代器。

// It's not clear how to call it:
// vec.iter().hit(...) does not compile
// vec.into_iter().hit(...) does not compile
//
impl<T, U> Hitable for T
where
T: Iterator<Item = U>,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.any(|h| h.hit(val))
}
}

尝试 #2:对于可以变成迭代器的东西。

// Does not compile as well:
//
// self.into_iter().any(|h| h.hit(val))
// ^^^^ cannot move out of borrowed content
//
impl<T, U> Hitable for T
where
T: IntoIterator<Item = U>,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.into_iter().any(|h| h.hit(val))
}
}

尝试#3:切片。

// This usage doesn't compile:
// let v = vec![Obj(2.0), Obj(3.0)];
// println!("{}", check_hit(&v));
//
// It says that Hitable is not implemented for vectors.
// When I convert vector to slice, i.e. &v[..], complains about
// unknown size in compilation time.
impl<T> Hitable for [T]
where
T: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.iter().any(|h| h.hit(val))
}
}

尝试 #4:迭代器 + 克隆

//     let v = vec![Obj(2.0), Obj(3.0)];
// println!("{}", check_hit(&v.iter()));
//
// does not compile:
// println!("{}", check_hit(&v.iter()));
// ^^^^^^^^^ `&Obj` is not an iterator
//
impl<T, U> Hitable for T
where
T: Iterator<Item = U> + Clone,
U: Hitable,
{
fn hit(&self, val: f64) -> bool {
self.clone().any(|h| h.hit(val))
}
}

Playground link

最佳答案

1。 迭代器-based

这行不通,因为迭代器需要可变才能推进它们,但您的特征需要 &self

2。基于IntoIterator

我会更改特征以按值获取 self,然后仅针对对 Obj 的引用实现它。这也允许为实现 IntoIterator 的任何类型实现它:

trait Hitable {
fn hit(self, val: f64) -> bool;
}

fn check_hit<T: Hitable>(world: T) -> bool {
world.hit(1.0)
}

struct Obj(f64);

impl Hitable for &'_ Obj {
fn hit(self, val: f64) -> bool {
self.0 > val
}
}

impl<I> Hitable for I
where
I: IntoIterator,
I::Item: Hitable,
{
fn hit(self, val: f64) -> bool {
self.into_iter().any(|h| h.hit(val))
}
}

fn main() {
let o = Obj(2.0);
let v = vec![Obj(2.0), Obj(3.0)];

println!("{}", check_hit(&o));
println!("{}", check_hit(&v));
}

另见:

3。基于切片

我发现阅读整个错误消息,而不仅仅是一行摘要,可以帮助:

error[E0277]: the size for values of type `[Obj]` cannot be known at compilation time
--> src/main.rs:28:20
|
28 | println!("{}", check_hit(&v[..]));
| ^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[Obj]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
note: required by `check_hit`
--> src/main.rs:5:1
|
5 | fn check_hit<T: Hitable>(world: &T) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

具体来说,这个位: 注意:check_hit 要求 — check_hit 要求 T尺寸。删除该限制允许此版本工作:

fn check_hit<T: Hitable + ?Sized>(world: &T) -> bool {
// ^~~~~~~~
world.hit(1.0)
}

另见:

关于generics - 如何为任何元素序列实现特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55148334/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com