0

I have a very simple case where I have some function that takes a Option<Vec>, it then needs to look at that option, and if it is a None, then have a empty byte string, but if it is a Some, then call a function that does some transofmration of it's input.

Sketched out, it looks like this:

pub fn transform(ad: &[u8]) -> Vec<u8> {
    ad.to_vec()

}
pub fn func(plaintext: Option<Vec<u8>>) {
    let out = "".as_bytes();
    if plaintext != None {
        let out = transform(&plaintext.unwrap());
}
}

Doing the unwrapping and the if like this is really ugly though,and I would much like to do this in a safer way, maybe with pattern matching:

pub fn transform(ad: &[u8]) -> Vec<u8> {
    ad.to_vec()

}
pub fn func(plaintext: Option<Vec<u8>>) {

let out = match plaintext {
    Some(x) =>  &transform(&x),
    None => "".as_bytes()
};

}

But this gives the error:

    |
16 |     let out = match plaintext {
   |         --- borrow later stored here
17 |         Some(x) =>  &return_smth(&x),
   |                      ^^^^^^^^^^^^^^-
   |                      |             |
   |                      |             temporary value is freed at the end of this statement
   |                      creates a temporary which is freed while still in use
   |
   = note: consider using a `let` binding to create a longer lived value

I am unsure about which value that is being talked about here. How do I call my function, and get a slice returned?

Grazosi
  • 603
  • 1
  • 10
  • 1
    Please post the full error message. Also, please format your code. A playground link will be good. – Chayim Friedman Apr 24 '22 at 22:20
  • Where is `return_smth()` defined? – Chayim Friedman Apr 24 '22 at 22:31
  • The code you posted is incomplete, inconsistent, and doesn't even parse. Please edit your question to something we can understand. – JMAA Apr 24 '22 at 23:30
  • Does this answer your question? [How do I make format! return a &str from a conditional expression?](https://stackoverflow.com/questions/54222905/how-do-i-make-format-return-a-str-from-a-conditional-expression) – Caesar Apr 25 '22 at 00:38
  • 1
    IIUC, you want [`map`](https://doc.rust-lang.org/1.54.0/std/option/enum.Option.html#method.map), as in : `let out = plaintext.map (transform).unwrap_or (vec![]);` – Jmb Apr 25 '22 at 06:56
  • @Jmb requires either an adaption step (`.as_deref()`) or updating `transform` tho), as `Option::::map` can't cope with an `fn(&T) -> U`. – Masklinn Apr 25 '22 at 07:40

1 Answers1

0

I am unsure about which value that is being talked about here.

The one that's returned by transform (or return_smth, or whatever else you call it): that returns a Vec (which is an owned value), you immediately borrow it to a slice, but you never actually store the vec, so at the end of the expression it gets dropped and you have a dangling reference.

How do I call my function, and get a slice returned?

There are two main ways:

You don't, would be my first recommendation here. Rust has a container called Cow which stores "an owned value or a reference", which you can use like a normal reference, or convert to an owned value:

    let out = match plaintext {
        Some(x) => transform(&x).into(),
        None => b"".into(),
    };

The second possibility is to store the owned at the highest level you need it, then create a local borrow to that e.g.

    let mut _v;
    let out = match plaintext {
        Some(x) => {
            _v = transform(&x);
            &*_v
        },
        None => b"",
    };

This is a relatively common pattern for non-trivial code paths where you need to borrow part of the owned value rather than the entirety of it.

Incidentally,

  • as you can see above Rust has bytes literals (b""), no need to create a string then byteify it

  • as jmb commented, Rust has high-level methods for common generic tasks. Both "apply transformation to option's value" and "get value or return default" are such

  • Vec::new() is guaranteed not to allocate, so creating an empty Vec (or String) is not a big deal.

    Hence if you don't have a very strong reason to favor a slice

    let out = plaintext
        .as_deref()
        .map_or_else(Vec::new, transform);
    

    would be perfectly fine here, or even

        let out = plaintext.map_or_else(Vec::new, transform);
    

    if you change transform to take and return a Vec.

Masklinn
  • 34,759
  • 3
  • 38
  • 57