These are chat archives for rust-lang/rust

1st
Jun 2018
Fredrik Portström
@portstrom
Jun 01 2018 10:46

Is there a way to conditionally pop something off a Vec with pattern matching? I have the following:

enum Item {
    A(String),
    B
}

fn example(stack: &mut Vec<Item>) {
    …
}

In the function I want to pop the last item off the stack and move the contained string if it matches the variant A, but leave the stack unchanged if the item matches the variant B.

Dmitriy
@dpogretskiy
Jun 01 2018 11:09
#[derive(Debug)]
pub enum Example {
    A(String),
    B,
}

fn example(data: &mut Vec<Example>) {
    let do_pop;

    match data.last() {
        Some(Example::A(string)) => do_pop = true,
        _ => do_pop = false,
    }

    if do_pop {
        let smth: Option<Example> = data.pop();
        std::mem::forget(smth);
    }
}

fn main() {
    let mut data = vec![Example::B, Example::A("ouch".into())];
    let mut data2 = vec![Example::A("ouch".into()), Example::B];

    example(&mut data);
    example(&mut data2);

    println!("{:?}", data);
    println!("{:?}", data2);
}
@portstrom something like this?
alternatively you can pop something and then put it back
Fredrik Portström
@portstrom
Jun 01 2018 11:17

@dpogretskiy I don't understand the point of forget. I suppose it leaks the memory, but doesn't move the string. The pattern just gets a reference to the string (since ref is implicit in the last version of Rust).

I'm leaning towards popping anything without discrimination and then putting it back. It's not a pretty solution though.

Dmitriy
@dpogretskiy
Jun 01 2018 11:18
nah, it's just example that you can do whatever you want with it
bad one, for sure :smile:
Michal 'vorner' Vaner
@vorner
Jun 01 2018 11:19

Also, you probably could so something like:

let do_pop = if let Some(Example::A(_)) = data.last() {
  true
} else {
  false
};

That's probably shorter and a bit more idiomatic.

Dmitriy
@dpogretskiy
Jun 01 2018 11:20
:+1: totally
i didn't bother much, i just mean, you can't do it in one step, there are always 2 at least
Fredrik Portström
@portstrom
Jun 01 2018 11:29
The problem with matching on last and then getting the value with pop is that the value from pop never went through the match expression, so you don't have access to the variant that was matched.
I'm making a parser for wiki text. Possibly the most awful markup language ever invented.
Michal 'vorner' Vaner
@vorner
Jun 01 2018 11:30
You could do a macro that copy-pastes the pattern to both places. And I saw slack markup, which is probably even worse.
Fredrik Portström
@portstrom
Jun 01 2018 11:34
Then the second incarnation of the match expression would have some unfortunate unreachable!() arms that should be unnecessary. It's a clever solution, but I think I prefer pop and push back for simplicity.
Andrey Lesnikov
@ozkriff
Jun 01 2018 11:39

maybe slice patterns can help to some extent

#![feature(slice_patterns)]

fn main()  {
    let v: Vec<u8> = vec![1, 2, 3];
    match v.as_slice() {
        &[1, ..] => println!("1"),
        _ => println!("2"),
    }
}

but they are not stable yet

Fredrik Portström
@portstrom
Jun 01 2018 11:40
No doubt Slack markup is an awful format, but its awfulness is at least bounded. It's parsed in a single pass with just a few rules to pay attention to. Wiki text on the other hand has an enormous set of rules and is parsed in many passes, like running 10 C preprocessors one after the other, each one changing the syntax parsed by the next one. To parse wiki text into a structured format however, I can only do one pass.
Andrey Lesnikov
@ozkriff
Jun 01 2018 11:44
hmm, or you can try something like this - http://play.rust-lang.org/?gist=ccabccd5778d28208e8c50057b8a73e6
Fredrik Portström
@portstrom
Jun 01 2018 11:45
@ozkriff Slice patterns seem to do the same thing as last. A slice doesn't give ownership of the items. The goal is to take ownership of the string contained in the item when it's taken off the stack.
John Hughes
@jondo2010
Jun 01 2018 14:17
Hi, if I have a fn foo() -> (T1, T2), is there a way that I can call it, destructure the tuple, reconstruct the tuple wrapping each item, all in one line? i.e., to obtain (bar(T1), bar(T2))?
Michal 'vorner' Vaner
@vorner
Jun 01 2018 14:30

Are you asking about one line or one expression? One can put as many statements on one line as one wants. :trollface: But if you want is one expression, block is also an expression, so something like:

{ let (a, b) = call(); (bar(a), baz(b)) }

will do what you need.

John Hughes
@jondo2010
Jun 01 2018 14:30
haha, yeah, my bad. One expression I mean :D
Thanks
Dmitriy
@dpogretskiy
Jun 01 2018 14:31
you can't map the tuple, as it's heterogeneous
as i can see, T1 isn't same as T2, but they both have some trait that allows bar(T1) and bar(T2)
that means you can't put them in one basket, so only manually, like vorner suggested
John Hughes
@jondo2010
Jun 01 2018 14:36
What if they were both the same type?
I can use (T,T).map()?
Dmitriy
@dpogretskiy
Jun 01 2018 14:36
then you can return array
not that simple :smile:
John Hughes
@jondo2010
Jun 01 2018 14:36
The function returning the tuple is in an external crate, so not that simple :)
Dmitriy
@dpogretskiy
Jun 01 2018 14:37
then you can't :smirk:
you can do something wonky, but it will be more code opposed to less :trollface:
Fredrik Portström
@portstrom
Jun 01 2018 14:45
Some(call()).map(|(a, b)| (bar(a), baz(b))).unwrap() if you by all means want to use the map function. But why would you do that? Just do let (a, b) = call().
John Hughes
@jondo2010
Jun 01 2018 14:47
Yeah. I guess I was just wondering if there was some cool syntax like (bar(_), bar(_)) = foo()
Dmitriy
@dpogretskiy
Jun 01 2018 14:48
nah, that would break stuff
Fredrik Portström
@portstrom
Jun 01 2018 14:52

This syntax is somewhat cool:

match example() {
    (a, b) => (bar(a), baz(b))
}

http://play.rust-lang.org/?gist=580ea7f53388e1668f32f0986066df68

Just think of match as map ;)
Ryan
@rnleach
Jun 01 2018 16:31
Is anybody aware of a good crate for lazy evaluation? Or just an idiomatic pattern for it? I found the lazy crate, but it seems abandoned.
Ryan
@rnleach
Jun 01 2018 18:08
@ozgurakkurt Sorry, guess I should have been more clear. I need them to not be static. I'm loading a bunch of data and I don't want to run an analysis on the data unless I need to draw it, which isn't always the case. The thing is I may toggle that display off and on, and I don't want to re-run the analysis every time.
ozgurakkurt
@ozgurakkurt
Jun 01 2018 18:16
impl<T> Cacher<T>
    where T: Fn(u32) -> u32
{
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            value: None,
        }
    }

    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            },
        }
    }
}
@rnleach You could add a toggle to this struct.
Ryan
@rnleach
Jun 01 2018 18:55
@ozgurakkurt That looks good, it'll get me started. I may need to use more generics for the function. Thank you.