About borrowing used only in trait arguments

struct StructA<A,B=A>{
    _marker: PhantomData<fn() -> (A, B)>
}

When

struct StructB{
    a:StructA<isize,&[u8]>
}

It hurts that I can't do things like this.

The reason why I want to do this is

trait TraitA<A,B> {
    fn convert_value(&mut self, input: B) -> A;
}

impl TraitA<isize,&[u8]> for StructB{
    fn convert_value(&mut self, input: &[u8]) -> isize;
        todo!("convert from input to isize value.")
    }
}

Because I want to do something like this.

If I used Vec instead of &[u8], the compilation passed, but In that case, ownership needs to be passed to the input of convert_value, which in some cases requires a clone, which I have a feeling is not good if the value is fat.

The problem is that &[u8] doesn't need to be stored anywhere in the struct at all, but it requires a lifetime. Since it is not saved, there is no problem as long as it remains alive only while the method is being executed.

In cases like this, if you just specify it as a type parameter, isn't there a need to go through the Borrow checker? Is it possible to make a modification that determines whether the data will eventually be saved in a struct (= whether the Size will eventually become 1 or more) and perform a Borrow check only in that case?

I'm not sure how helpful this is in your specific case, but this works:

use std::marker::PhantomData;

struct StructA<A,B=A>
where B: ?Sized
{
    _marker: PhantomData<for<'a> fn(&'a B) -> A>
}

struct StructB{
    a: StructA<isize, [u8]>
}

Having the &'a B in the return type failed because the borrow checker noted that a nullary function can not possibly return a reference with arbitrary lifetime.

You may be able to get away with a ConvertRef and ConvertOwned traits where the first uses this for<'a> trick. But then again, it also works without the for<'a> bit. What I think you want here is to say StructA<A, for<'a> &'a B> but that triggered a reference to this tracking issue.

2 Likes

Thank you for your reply.

I learned that "?Sized" is used in these cases.

eventually,

trait TraitA<T, I: ?Sized> {
    fn convert_value(&mut self, input: &I) -> T;
}

pub struct StructA<T, I: ?Sized = T> {
    _marker: PhantomData<fn(I, T)>,
}


pub struct StructB<T, I: ?Sized = T> {
    triee: StruictA<T, I>,
}

impl TraitA<isize,[u8]> for StructB{
    fn convert_value(&mut self, input: &[u8]) -> isize;
        todo!("convert from input to isize value.")
    }
}

I solved it by doing this.

I don't like the unnecessary clone() call when I=T as shown below.

impl TraitA<X,X> for StructX{
    fn convert_value(&mut self, input: &X) -> X;
        input.clone()
    }
}

However, I think this may be a good idea since even if the argument involves a transfer of ownership, memory will still be copied to the stack.

thank you.