Why does this compile:
fn main() {
let xs = [||1, ||2, ||3];
}
but this does not?
fn main() {
let xs = [(||1, 1), (||2, 2), (||3, 3)] ;
}
EDIT: To be clear, the question is not why does it not compile. It is what is the difference between these two that makes the first compile but the second does not?.
The first case is special cased in the compiler: when some types are required to unify (such as when all of them are elements of the same array), and all of them are non-capturing closures, the compiler automatically coerces them to function pointers. This does not work if they are tuple that contain non-capturing closures, however.
The relevant code in rustc is here, if you're interested.
Related
I've seen a lot of usage of Box::new in Rust language.
https://doc.rust-lang.org/book/ch15-01-box.html
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
However, I think this is a bit redundant, especially, in the code like this:
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
Now, I want to write in a concise way using Macro as we've seen as vec!
https://doc.rust-lang.org/book/ch19-06-macros.html?highlight=vec#declarative-macros-with-macro_rules-for-general-metaprogramming
let v: Vec<u32> = vec![1, 2, 3];
so that with box! macro, we could write:
fn main() {
let b = box!(5);
println!("b = {}", b);
}
or
fn main() {
let list = Cons(1, box!(Cons(2, box!(Cons(3, box!(Nil))))));
}
My question is
Is there any reason that box! macro is not popular even it's
used frequently in Rust?
What is the proper way to define the macro? Is there any points of attention?
This is a bit subjective, but vectors are used far more often, I believe. And the vec! macro saves you a lot more code compared to the box! macro you are referring to.
As for the macro implementation, you can write something like this:
macro_rules! bx {
($e:expr) => {
Box::new($e)
};
}
Here is an example usage:
let b = Box::new(3);
let m = bx!(7);
Note that I named it bx! and not box!, as the latter is a reserved word in Rust.
however, for some unknown reason Rust guys prefer to use macro for vec! or println!
I suggest asking this the other way around: why couldn't vec! and println! be functions? And the answer is, both are variadic (can take variable number of arguments) and there are no variadic functions in Rust. It's much worse for println!, whose arguments can have different types too; and constraints on those types depend on the first argument! Try writing down a type for println as a function, and you'll find it would be much less usable and less efficient.
The problem vec! solves is smaller. But as Chayim Friedman's comment says, until quite recently you couldn't even have had
Vec::from([1,2,3])
if there were no vec! macro. I think the best you could have done was
Vec::from(&[1,2,3])
As Chayim points out, this is strictly worse than vec!.
Of course, Box::new doesn't have this problem at all. So it's a function just because it didn't have to be a macro.
but as I post the Cons list expample, it's obvious the latter syntax is redundant and does have an issue for readability
In that case box! is no less redundant; instead a way to get rid of redundancy is
fn cons(head: i32, tail: List) -> List {
List::Cons(head, Box::new(tail))
}
and then
let list = cons(1, cons(2, cons(3, Nil)));
Or even a list! macro and
let list = list![1,2,3];
Thanks to #at54321, I googled and found
https://doc.rust-lang.org/beta/unstable-book/language-features/box-syntax.html
#![feature(box_syntax)]
fn main() {
let b = box 5;
}
So, already there.
I am a Rust newbie, I tested following code and got a question. Is type of slice [T]?If so, [T] is unsized, but it passed when I compiled the code. Why is that?
#[test]
fn test_scilce(){
let v = vec!['a', 'b', 'v'];
let slice = (v[1..3]).into_iter();
// let s: String = slice.collect();
println!("{:?}", slice);
println!("{:?}", v);
}
Since [T]::into_iter(self) doesn't exist, but [T]::into_iter(&self) does, the compiler inserts the missing reference and treats (v[1..3]).into_iter() as (&v[1..3]).into_iter(). That is in turn the same as (&v[1..3]).iter() and gives out references to the elements of the vector. (There is even a clippy lint warning you of using into_iter() on slice or other references.)
The same auto-referencing mechanism is what allows you to write v.len() instead of the "correct" (&v).len(), despite Vec::len taking &self.
I want to create a vector of functions
let all_rerankers = vec![ match_full
, match_partial
, match_regex
, match_camel_case
];
However, match_camel_case needs one more parameter than other functions, so I though I could define a closure for match_camel_case
// 3 is the extra parameter needed by match_camel_case
let close_camel_case = |str: &str, keyword: &str| {
match_camel_case(str, keyword, 3)
};
and then specify the type of my vector:
let all_rerankers: Vec<|str: &str, kwd: &str| -> MatchScore>
= vec![ match_full
, match_partial
, match_regex
, close_camel_case
];
However compiling it shows me that Rust treats them differently:
mismatched types: expected `fn(&str, &str) -> MatchScore`,
found `|&str, &str| -> MatchScore`
(expected extern fn, found fn)
close_camel_case
^~~~~~~~~~~~~~~~
(and similar type error in my vec! macro)
It also seem to distinguish between Fn type and closure type. I can make this compile by wrapping every match_* function in a closure, but I'm sure there's a better solution.
Question:
What is the actual mismatch here? the error message seems to suggest Fn vs closure type, but then there's also expected extern fn, found fn in the error message
How can I make the type match? (namely, convert closure into fn type, since it's pure)
my rustc version: rustc 0.12.0-pre-nightly (09cebc25a 2014-09-07 00:31:28 +0000) (can upgrade if needed)
This looks like some unfortunate problem in type inference. If you do this:
let mut all_rerankers: Vec<|str: &str, kwd: &str| -> MatchScore> = Vec::new();
all_rerankers.push(match_full);
all_rerankers.push(match_partial);
all_rerankers.push(match_regex);
all_rerankers.push(close_camel_case);
Then everything is fine. The duplication is extensive, but you can easily write a macro whose invocation could look like this:
push_to!(all_rerankers;
match_full,
match_partial,
match_regex,
close_camel_case
)
This probably deserves creating an issue in Rust bug tracker, but old closures will be deprecated soon, so I'm not sure if this is worth fixing.
I have two dummy functions:
fn foo() -> u32 { 3 }
fn bar() -> u32 { 7 }
And I want to create a boxed slice of function pointer: Box<[fn() -> u32]>. I want to do it with the box syntax (I know that it's not necessary for two elements, but my real use case is different).
I tried several things (Playground):
// Version A
let b = box [foo, bar] as Box<[_]>;
// Version B
let tmp = [foo, bar];
let b = box tmp as Box<[_]>;
// Version C
let b = Box::new([foo, bar]) as Box<[_]>;
Version B and C work fine (C won't work for me though, as it uses Box::new), but Version A errors:
error[E0605]: non-primitive cast: `std::boxed::Box<[fn() -> u32; 2]>` as `std::boxed::Box<[fn() -> u32 {foo}]>`
--> src/main.rs:8:13
|
8 | let b = box [foo, bar] as Box<[_]>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
Apparently, for some reason, in the version A, the compiler isn't able to coerce the function items to function pointers. Why is that? And why does it work with the additional temporary let binding?
This question was inspired by this other question. I wondered why vec![foo, bar] errors, but [foo, bar] works fine. I looked at the definition of vec![] and found this part which confused me.
This looks like an idiosyncracy of the type inference algorithm to me, and there probably is no deeper reason for this except that the current inference algorithm happens to behave like it does. There is no formal specification of when type inference works and when it doesn't. If you encounter a situation that the type inference engine cannot handle, you need to add type annotations, or rewrite the code in a way that the compiler can infer the types correctly, and that is exactly what you need to do here.
Each function in Rust has its own individual function item type, which cannot be directly named by syntax, but is diplayed as e.g. fn() -> u32 {foo} in error messages. There is a special coercion that converts function item types with identical signatures to the corresponding function pointer type if they occur in different arms of a match, in different branches of an if or in different elements of an array. This coercion is different than other coercions, since it does not only occur in explicitly typed context ("coercion sites"), and this special treatment is the likely cause for this idiosyncracy.
The special coercion is triggered by the binding
let tmp = [foo, bar];
so the type of tmp is completely determined as [fn() -> u32; 2]. However, it appears the special coercion is not triggered early enough in the type inference algorithm when writing
let b = box [foo, bar] as Box<[_]>;
The compiler first assumes the item type of an array is the type of its first element, and apparently when trying to determine what _ denotes here, the compiler still hasn't updated this notion – according to the error message, _ is inferred to mean fn() -> u32 {foo} here. Interestingly, the compiler has already correctly inferred the full type of box [foo, bar] when printing the error message, so the behaviour is indeed rather weird. A full explanation can only be given when looking at the compiler sources in detail.
Rust's type solver engine often can't handle situations it should theoretically be able to solve. Niko Matsakis' chalk engine is meant to provide a general solution for all these cases at some point in the future, but I don't know what the status and the timeline of that project is.
[T; N] to [T] is an unsizing coercion.
CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U> is
implemented for all pointer types (including smart pointers like Box
and Rc). Unsize is only implemented automatically, and enables the
following transformations:
[T; n] => [T]
These coercions only happen at certain coercion sites:
Coercions occur at a coercion site. Any location that is explicitly
typed will cause a coercion to its type. If inference is necessary,
the coercion will not be performed. Exhaustively, the coercion sites
for an expression e to type U are:
let statements, statics, and consts: let x: U = e
Arguments to functions: takes_a_U(e)
Any expression that will be returned: fn foo() -> U { e }
Struct literals: Foo { some_u: e }
Array literals: let x: [U; 10] = [e, ..]
Tuple literals: let x: (U, ..) = (e, ..)
The last expression in a block: let x: U = { ..; e }
Your case B is a let statement, your case C is a function argument. Your case A is not covered.
Going on pure instinct, I'd point out that box is an unstable magic keyword, so it's possible that it's just half-implemented. Maybe it should have coercions applied to the argument but no one has needed it and thus it was never supported.
I have been playing with Rust by porting my Score4 AI engine to it - basing the work on my functional-style implementation in OCaml. I specifically wanted to see how Rust fares with functional-style code.
The end result: It works, and it's very fast - much faster than OCaml. It almost touches the speed of imperative-style C/C++ - which is really cool.
There's a thing that troubles me, though — why do I need two ampersands in the last line of this code?
let moves_and_scores: Vec<_> = moves_and_boards
.iter()
.map(|&(column,board)| (column, score_board(&board)))
.collect();
let target_score = if maximize_or_minimize {
ORANGE_WINS
} else {
YELLOW_WINS
};
if let Some(killer_move) = moves_and_scores.iter()
.find(|& &(_,score)| score==target_score) {
...
I added them is because the compiler errors "guided" me to it; but I am trying to understand why... I used the trick mentioned elsewhere in Stack Overflow to "ask" the compiler to tell me what type something is:
let moves_and_scores: Vec<_> = moves_and_boards
.iter()
.map(|&(column,board)| (column, score_board(&board)))
.collect();
let () = moves_and_scores;
...which caused this error:
src/main.rs:108:9: 108:11 error: mismatched types:
expected `collections::vec::Vec<(u32, i32)>`,
found `()`
(expected struct `collections::vec::Vec`,
found ()) [E0308]
src/main.rs:108 let () = moves_and_scores;
...as I expected, moves_and_scores is a vector of tuples: Vec<(u32, i32)>. But then, in the immediate next line, iter() and find() force me to use the hideous double ampersands in the closure parameter:
if let Some(killer_move) = moves_and_scores.iter()
.find(|& &(_,score)| score==target_score) {
Why does the find closure need two ampersands? I could see why it may need one (pass the tuple by reference to save time/space) but why two? Is it because of the iter? That is, is the iter creating references, and then find expects a reference on each input, so a reference on a reference?
If this is so, isn't this, arguably, a rather ugly design flaw in Rust?
In fact, I would expect find and map and all the rest of the functional primitives to be parts of the collections themselves. Forcing me to iter() to do any kind of functional-style work seems burdensome, and even more so if it forces this kind of "double ampersands" in every possible functional chain.
I am hoping I am missing something obvious - any help/clarification most welcome.
This here
moves_and_scores.iter()
gives you an iterator over borrowed vector elements. If you follow the API doc what type this is, you'll notice that it's just the iterator for a borrowed slice and this implements Iterator with Item=&T where T is (u32, i32) in your case.
Then, you use find which takes a predicate which takes a &Item as parameter. Sice Item already is a reference in your case, the predicate has to take a &&(u32, i32).
pub trait Iterator {
...
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where P: FnMut(&Self::Item) -> bool {...}
... ^
It was probably defined like this because it's only supposed to inspect the item and return a bool. This does not require the item being passed by value.
If you want an iterator over (u32, i32) you could write
moves_and_scores.iter().cloned()
cloned() converts the iterator from one with an Item type &T to one with an Item type T if T is Clone. Another way to do it would be to use into_iter() instead of iter().
moves_and_scores.into_iter()
The difference between the two is that the first option clones the borrowed elements while the 2nd one consumes the vector and moves the elements out of it.
By writing the lambda like this
|&&(_, score)| score == target_score
you destructure the "double reference" and create a local copy of the i32. This is allowed since i32 is a simple type that is Copy.
Instead of destructuring the parameter of your predicate you could also write
|move_and_score| move_and_score.1 == target_score
because the dot operator automatically dereferences as many times as needed.