I understand this is illegal in Rust:
trait A { }
struct S { a: A, b: A }
The reason is that all members except the last one must be sized, and a trait is not sized.
Does this mean it is impossible to have a struct/tuple of traits? How would I return a pair of values from a function and I only know that they implement a certain trait?
You've already identified the problem of type being not sized, so you just need to turn it into sized type.
If you don't own the objects, you may use reference.
struct S1<'a> {
a: &'a A,
b: &'a A,
}
You can use two lifetimes instead of one if they are different.
struct S1<'a, 'b> {
a: &'a A,
b: &'b A,
}
If you want to own the objects, you may use Box.
struct S2 {
a: Box<A>,
b: Box<A>,
}
Further, if you know the concrete type at compile time, and you just want to write generic code, you can write generic struct too
struct S3<A1: A, A2: A> {
a: A1,
b: A2,
}
In S3, each A1 or A2 represents a concrete type that implements trait A when you instantiate it in your code.
Related
Created a simple struct that implements Sized trait.
struct FixedIndividual<T: Sized,A: cmp::Ord, >{
chromosome: T,
score: Option<A>,
}
impl<T: Sized, A: cmp::Ord> FixedIndividual<T,A>{
fn new(chromosome: T) -> Self{
FixedIndividual { chromosome , score: None}
}
}
However, I've managed to create an instance that includes Vec(implement only ?Size),
#[test]
fn init_vector(){
let chromosome: Vec<i32> = vec![1,2,3,4,5];
let chromosome_cpy = chromosome.clone();
let indv:FixedIndividual<Vec<i32>, OrderedFloat<f64>> = FixedIndividual::new(chromosome);
assert_eq!(indv.score, None);
assert_eq!( indv.chromosome
.iter()
.zip(chromosome_cpy.iter())
.all(|(a,b)| a == b ), true);
}
Created a simple struct that implements Sized trait.
Your bounds are useless, generic bounds are Sized by default, you have to opt out of it.
However, I've managed to create an instance that includes Vec(implement only ?Size),
Not sure where you got that idea, and ?Sized is not a trait, it's only a bound which means the type (or function) is sizedness-agnostic. That doesn't imply it's unsized itself. For instance Box<T> has T: ?Sized, meaning T may be sized or unsized. Box is sized either way.
A type being unsized means it implements !Sized, which rather few types do.
That's fine because Vecs are Sized, like almost all struct values. The actual Vec value does not contain its elements, but instead references them, so it has a defined, constant size no matter how many elements there are, similar to how a pointer is stored in an integer value. You may also have confused vecs with slices, such as [i32], which are ?Sized.
I have the following for a merge sort problem with huge files:
struct MergeIterator<'a, T> where T: Copy {
one: &'a mut dyn Iterator<Item=T>,
two: &'a mut dyn Iterator<Item=T>,
a: Option<T>,
b: Option<T>
}
impl<'m, T> MergeIterator<'m, T> where T: Copy {
pub fn new(i1: &'m mut dyn Iterator<Item=T>,
i2: &'m mut dyn Iterator<Item=T>) -> MergeIterator<'m, T> {
let mut m = MergeIterator {one:i1, two:i2, a: None, b: None};
m.a = m.one.next();
m.b = m.two.next();
m
}
}
This seems to make rustc happy. However, I started with this (imho) less clumsy body of the new() function:
MergeIterator {one:i1, two:i2, a: i1.next(), b: i2.next()}
and got harsh feedback from the compiler saying
cannot borrow `*i1` as mutable more than once at a time
and likewise for i2.
I'd like to understand where the semantic difference is between initializing the data elements through the m.one reference vs the i1 argument? Why must I write clumsy imperative code here to achieve what I need?
This will probably be clearer if you write it in lines so that the sequence of operations is visible:
MergeIterator {
one: i1,
two: i2,
a: i1.next(),
b: i2.next(),
}
You're giving i1 to the new struct, you don't have it anymore to call next.
The solution is to change the order of operations to call next first before giving away the mutable reference:
MergeIterator {
a: i1.next(),
b: i2.next(),
one: i1,
two: i2,
}
To make it clearer, you must understand that i1.next() borrows i1 only for the time of the function call while i1 gives away the mutable reference. Reversing the order isn't equivalent.
I am working on a actor project which need alias for the trait because it is so long, but even with the nightly feature #![feature(trait_alias)] seems can not achieve.
In short I write a playground:
I want alias A<T> to be shorter causing I have many generic type on A in real case; and the same time I want to access the type Output = Self; from its implementations B.
Appreciate for any help.
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=5a9bb8d3f76112c0b73ea1da8af34959
#![feature(trait_alias)]
trait A<T> {
type Output;
fn test(a: T) -> Self::Output;
}
//To alias the trait, real situation longer than this.
//attempt 1:
trait B: A<String>{}
//attempt 2:
//trait B : A<String, Output=Self> where Self: std::marker::Sized {}
//impl<T> B for T where T: A<String, Output=T> {}
//attempt 3 with trait_alias:
//trait B = A<String>;
struct SA;
impl B for SA {
type Output = Self;
}
trait alias is only mean to be:
used wherever traits would normally be used as either bounds or trait objects. Source
So, your use case doesn't match, you can't do that.
The general setup is I have an array of values I'd like to map() and then chain() with 1 additional value. I've learned from this answer that the proper way to construct that final value is to use std::iter::once. This works and eliminated the below problem, but I would still like to understand it better.
In my broken, likely rust-anti-pattern-riddled example, I was using an array of a single element and then calling into_iter(). This produced a value / reference type-mismatch in the chain.
Question: What is the Rust-idiomatic mechanism for correcting this value / reference mismatch? Particularly if clone and copy are unavailable.
Background: Why is there a type mis-match to begin with?
This much I believe I understand. Based on the definition of std::iter::Map, the item type for the iterator is type Item = B where B is constrained by F: FnMut(<I as Iterator>::Item) -> B (i.e. the mapped type). However array defines the following 2 IntoIterator implementations, both of which appear to produce references.
impl<'a, const N: usize, T> IntoIterator for &'a [T; N] where
[T; N]: LengthAtMost32,
type Item = &'a T
impl<'a, const N: usize, T> IntoIterator for &'a mut [T; N] where
[T; N]: LengthAtMost32,
type Item = &'a mut T
Example demonstrating the issue:
#[derive(PartialEq, Eq, Clone, Copy)]
enum Enum1 {
A, B, C
}
#[derive(PartialEq, Eq, Clone, Copy)]
enum Enum2 {
X, Y, Z
}
struct Data {
// Other data omitted
e1: Enum1,
e2: Enum2
}
struct Consumer {
// Other data omitted
/** Predicate which evaluates if this consumer can consume given Data */
consumes: Box<dyn Fn(&Data) -> bool>
}
fn main() {
// Objective: 3 consumers which consume data with A, B, and X respectively
let v: Vec<Consumer> = [Enum1::A, Enum1::B].iter()
.map(|&e1| Consumer { consumes: Box::new(move |data| data.e1 == e1) })
// This chain results in an iterator type-mismatch:
// expected &Consumer, found Consumer
.chain([Consumer { consumes: Box::new(move |data| data.e2 == Enum2::X) }].into_iter())
.collect(); // Fails as well due to the chain failure
}
Error:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, Consumer> as std::iter::IntoIterator>::Item == Consumer`
--> src/main.rs:52:10
|
52 | .chain([Consumer { consumes: Box::new(move |data| data.e2 == Enum2::X) }].into_iter())
| ^^^^^ expected reference, found struct `Consumer`
|
= note: expected type `&Consumer`
found type `Consumer`
Rust playground example.
There is a long-standing issue regarding this. The technical details are a bit heavy, but essentially, due to underlying, technical reasons, you cannot take ownership of a fixed-size array and return owned references without a lot of hocus pocus. This becomes obvious when you think about what a fixed-size array is and how it is stored in memory, and how you can get elements out without cloning them.
As a result, due to the implementations you found already, you can only get borrowed references. You can bypass this with arrayvec (as they have a sound implementation of IntoIterator for ArrayVec with owned types), or you can require that all your T: Clone and deal with it that way, at a cost of extra items in memory (temporarily; 90% of the time the compiler optimizes this away).
I just ran into an issue in some code of mine and managed to trim it down to the following minimal example :
use std::iter::IntoIterator;
use std::marker::PhantomData;
trait Bar<'a> {
fn compile_plz(&self) -> &'a str;
}
struct Foo<'a> {
ph: PhantomData<&'a str>
}
impl<'a> Bar<'a> for Foo<'a> {
fn compile_plz(&self) -> &'a str {
"thx"
}
}
fn do_something_with_bars<'a, I>(it: I) -> Result<(), ()> where I: IntoIterator<Item=&'a Bar<'a>> {
Ok(())
}
fn take_bar<'a, B>(b: &'a B) where B: Bar<'a> {
do_something_with_bars(vec![b]);
}
fn main() {
let f = Foo{ph: PhantomData};
take_bar(&f);
}
This fails with the following error :
23:5: 23:27 error: type mismatch resolving <collections::vec::Vec<&B> as core::iter::IntoIterator>::Item == &Bar<'_>:
expected type parameter,
found trait Bar [E0271]
However, changing vec![b] to vec![b as &Bar] works fine. But since b is of type &B, and B has a Bar<'a> bound, why can't the compiler figure out that b is indeed a &Bar?
It could theoretically attempt to 'fix' the type to &Bar. However, you're hitting the variance problem here - a vector of &B is not a vector of &Bar just because a &B is a &Bar, and neither is the inverse true.
Example: Say we treat a vector of &B as a vector of &Bar. Now we have a value of type &C where &C is a &Bar but not a &B - can we put a &C into our vector? Well, obviously not, because the implementation is a vector of &B. So we can only allow reads, not writes. On the other hand, we can attempt to treat a vector of &Bar as a vector of &B - this works fine as long as we only write &Bs into our vector (because it's allowed to accept &Bs of course) - but since it's still a vector of &Bar, it can contain things that aren't &Bs, so we aren't allowed to read from it.
Hence, a container that allows both read and write at the same time needs to be invariant in its generic argument. You'll always have this problems in languages that have both polymorphism and generics in this fashion.
So, back to the actual question: Since this problem exists, there can't be an automatic escape hatch that would turn your expression that is initially going to be inferred to be vector of &B to the type vector of &Bar. Be explicit about your types, and this won't happen.
Full type inference maybe could help here, but I'm not sure if full type inference is even possible in a language like rust.