Help, uppity Cow does not want to surrender

I have this struct that has a &str in it. I now realized that sometimes I need to include it in my error type. For the sake of simplicity I'd rather not contaminate my error type with the lifetime. Thus I thought hey, this must be a good opportunity to play around with Cow, as I generally don't have much use for it, but I can't seem to make an owned version of my struct with Cow. Is this possible at all? Or do I have to make a second struct without lifetime?

This is my attempt, but the Cow is having none of it.

/// The format actually in the CSV file.
/// Used for deserializing with Serde.
//
#[ derive( Debug, Deserialize) ]
//
pub(crate) struct CsvRecord<'a>
{
	r#type: Cow<'a, str>       ,
	client: u16                ,
	tx    : u32                ,
	amount: Option<BigDecimal> ,
}


impl<'a> std::borrow::ToOwned for CsvRecord<'a>
{
	type Owned = CsvRecord<'static>;

	fn to_owned( &self ) -> Self::Owned
	{
		let cow: Cow<'static, str> = self.r#type.clone().into_owned().into();

		Self
		{
			r#type: cow,
			// r#type: self.r#type.clone().into_owned().into(),
			// r#type: Cow::Owned( self.r#type.into_owned() ),
			client: self.client,
			tx    : self.tx,
			amount: self.amount.clone(),
		}
	}
}

Well, what is the problem (you can paste the error message)? Also, please format your code with rustfmt.

Playground for the error: Rust Playground

For rustfmt on the playground, top right click tools -> than rustfmt.

ToOwned isn't really the right trait to express this pattern. It's aimed at pairs of owned and borrowed types, like String/str or Vec<T>/[T]. Instead, to_owned() should just be its own method. Also, two other fixes are necessary. &'a self should be replaced with &self, since we don't need the self borrow to last as long as the type does. And the Self { ... } expression must be replaced with an explicit CsvRecord { ... }, since Self resolves to CsvRecord<'a>, but we need the type to resolve to CsvRecord<'static>. Altogether:

use std::borrow::Cow;
use bigdecimal::BigDecimal;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub(crate) struct CsvRecord<'a> {
    r#type: Cow<'a, str>,
    client: u16,
    tx: u32,
    amount: Option<BigDecimal>,
}

impl<'a> CsvRecord<'a> {
    fn to_owned(&self) -> CsvRecord<'static> {
        CsvRecord {
            r#type: self.r#type.clone().into_owned().into(),
            client: self.client,
            tx: self.tx,
            amount: self.amount.clone(),
        }
    }
}
2 Likes

Thanks alot. Self definitely tripped me up there. The &'a self was me trying to be more specific with which lifetimes referred to what in the hopes of pleasing the compiler.

Not quite sure why the compiler doesn't accept it when it's an impl for ToOwned.

Yeah, if you have a struct MyType<'a>, then you very rarely want to use &'a self on a method, even if the compiler suggests it. Intuitively, the 'a parameter means that we are borrowing data from outside the struct. An &'a self method could only be called if the struct lived exactly as long as the data it is borrowing, which isn't very helpful in general.

only be called if the struct lived exactly as long as the data it is borrowing

That's true of &'a mut self, but &'a self can sometimes be fine; it just means that, for the purposes of that one function call, the lifetimes in the struct are treated as if they were as short as the borrow of the struct itself. (This doesn't work with &mut because &mut lets you assign through it — data can flow both ways — and it wouldn't be okay to implicitly lengthen a short lifetime.)

1 Like