These are chat archives for rust-lang/rust

14th
Mar 2017
Stan Kondrat
@stan-kondrat
Mar 14 2017 19:48
Please, help solve this:
fn foo<F>(closure2: F) -> i32
    where F: Fn(i32) -> i32 { // problem here
    let closure3 = |x| x + 1;
    closure2(closure3)
}

fn main() {
    let closure1 = |x| x(1);
    let answer = foo(closure1);
    println!("{:?}", answer) // should be 2
}
Aleksey Kladov
@matklad
Mar 14 2017 19:50
Perhaps it should be something like F: Fn(F1) -> i32, F1: Fn(i32) -> i32?
Stan Kondrat
@stan-kondrat
Mar 14 2017 19:52
@matklad
2 |     where F: Fn(F1) -> i32, F1: Fn(i32) -> i32 { // problem here
  |                 ^^ undefined or not in scope
Ilya Bogdanov
@vitvakatu
Mar 14 2017 19:53
No, I got you problem
closure3 is closure, but your closure2 func have only one i32 argument
Stan Kondrat
@stan-kondrat
Mar 14 2017 19:55
right, I don't know how define nested where
Ilya Bogdanov
@vitvakatu
Mar 14 2017 19:56
Okay, than change code according to matklad's message.
Give me sec
Aleksey Kladov
@matklad
Mar 14 2017 19:57
@vitvakatu that won't work unfortunately: you'll need a for<> type
Ilya Bogdanov
@vitvakatu
Mar 14 2017 19:58
fn foo<F, F1>(closure2: F) -> i32
    where F: Fn(F1) -> i32, F1: Fn(i32) -> i32 { 
    let closure3 = |x| x + 1;
    closure2(closure3)
}

fn main() {
    let closure1 = |x| x(1);
    let answer = foo(closure1);
    println!("{:?}", answer) // should be 2
}
@matklad oh, maybe
Stan Kondrat
@stan-kondrat
Mar 14 2017 20:02
@vitvakatu thx, but still not working :-( https://is.gd/Ffcr0f
Aleksey Kladov
@matklad
Mar 14 2017 20:07
I think with current Rust you can't avoid dynamic dispatch in this case, so this should be the best you can get:
https://play.rust-lang.org/?gist=f9c5409c571542385a52cbdc287a3ce4&version=stable
Stan Kondrat
@stan-kondrat
Mar 14 2017 20:08
@matklad great! thank you so much :+1:
Christian Howe
@cjhowe7
Mar 14 2017 20:34
is there some way to expand lifetime elision so i can see what the compiler is doing?
Aleksey Kladov
@matklad
Mar 14 2017 20:36

@cjhowe not that I am aware of (there is a semi-broken version in intellij-rust, but I would not recommend it for serious use though).

But elision rules are rather easy to apply in one's head, once you understand them. Is there any particular code you are wondering about?

Christian Howe
@cjhowe7
Mar 14 2017 20:37
i mean, i guess i do have a more specific question, but i thought that'd be really useful to have
i feel like i can manage lifetimes better if i'm always explicit
Aleksey Kladov
@matklad
Mar 14 2017 20:38
Yep, lifetime elision definitely can cause some confusing errors in the wrong place :(
Christian Howe
@cjhowe7
Mar 14 2017 20:38
does something like fn foo(&'a u64, &'b u64) -> u64 mean that the lifetimes of 'a and 'b only last for the duration of the call to foo?
i mean, i have a lot of code that only needs to borrow pointers while it's being called, and there's no relationship between those lifetimes whatsoever
if i understand correctly, fn foo(&u64, &u64) -> u64 is the same as above with lifetime elision
Aleksey Kladov
@matklad
Mar 14 2017 20:40
yep, they are equivalent.

mean that the lifetimes of 'a and 'b only last for the duration of the call to foo?

I would say that 'a and 'b can be just any lifetime at all.

Explicit lifetimes are useful to connect things. That is, if you have fn foo(&'a Foo) -> Bar<'a>, then you know that input Foo and output Bar are connected.
A single unconstrained lifetime is just "any lifetime, I don't care at all".
Christian Howe
@cjhowe7
Mar 14 2017 20:49
i feel like i understand lifetimes, but i still fight the borrow checker
meh