What does: `|| ->` syntax mean?

I found this in the crate gym. Does this mean child will have type std::process::Child rather than std::thread::JoinHandle?

		let child = std::thread::spawn(|| -> std::process::Child {
			Command::new("python3")
				.arg("server.py")
				.arg("--listen")
				.arg(ip_str)
				.arg("--port")
				.arg(port_str)
				.stdout(Stdio::null())
				.spawn()
				.expect("Could not initiate server")
		});

It is the explicit return type on the inner closure, not on the spawn function. The closure will return Child, and spawn will return JoinHandle<Child>, correspondingly.

So in this case does it do anything?

Yes, the closure creates and then spawns the Command when it is called.

Explicit type might be necessary, if Rust is unable to infer it. Not sure if this is the case here. And the type parameter of JoinHandle is the thing you get on joining the thread.

In other languages it can be called anonymous function, or lambda, or closure. Specifically || part means that this closure does not have parameters. If it had, then it would be | param1, param2 | -> {...}.
Usually closure return type is not needed and will be iferred by compiler, for example || -> 3_u32 is the same as || -> u32 { 3_u32 }

1 Like

In the above code is it possible to make use of the return value, from the closure, in any way?

Note that this syntax isn't quite right. The following are valid, and equivalent:

|| 3u32
|| 3_u32
|| { 3u32 }
|| -> u32 { 3u32 }
|| -> u32 { 3u32 }
|| -> u32 { 3 }

On the other hand, || -> 3_u32 is not valid, as then 3_u32 is counted as the return type, and the closure has no body. The || declares the closure, and -> declares the return type. If no return type is specified, then you don't need ->. Note that this roughly matches function syntax, where you can write fn x() { ... } to return (), or fn x() -> u32 { ... } to return u32.

6 Likes

As I said before, the closure's return value becomes the return value of child.join().

1 Like

But does the return type do anything?

What do you mean by "does type do"? Types, AFAIK, can't do anything. Values can.
Or do you mean if the presence or absence of this return type changes anything? I'm not sure, but it may turn program failing to compile (due to type inference error) into one which compiles.

Types in Rust always exist, but they may be either explicitly specified by the programmer, or inferred by the compiler.

Functions always have explicit types:

fn double(x: i32) -> i32 { x * 2 }

Closures may have explicit types:

let double = |x: i32| -> i32 { x * 2 };

In many cases, the compiler has enough information to infer the type of a closure. In that case, the programmer may choose not to make the type explicit. This doesn't change the behavior of the closure; it's just a different way for the compiler to determine its type.

let double = |x| { x * 2 };

double(1i32); // This compiler can infer double's type from this.
4 Likes

Sorry, I am not being plain.
In that code I quoted above || -> std::process::Child what I mean is is there and practical effect of declaring the return type of the closure?

AFAICT there is not. The std::process::Child is discarded so its type is irrelevant.
But then why bother declaring it? So I am doubting myself, so I am asking.

The Child is not discarded. It's returned from the closure, and can be accessed through the JoinHandle returned from std::thread::spawn.

1 Like