Editor's note: This question was asked before Rust 1.0 and some of the syntax has changed since then, but the underlying concepts remain. Some answers have been updated for Rust 1.0 syntax.
I'm new to Rust and trying to do something with closures which is trivial in JavaScript, Python, etc. but I am running into lifetime issues in Rust. I understand the error message, but it leads me to believe what I want to do is pretty hard in Rust.
I just want to create an array of functions, a, such that
a[0] is the function returning 0
a[1] is the function returning 1
...
a[9] is the function returning 9
I tried:
fn main() {
let a : [||->uint, ..10];
for i in range(0u, 10) {
a[i] = ||{i};
}
println!("{} {} {}", a[1](), a[5](), a[9]())
}
But I got a lifetime error. The reported error was "cannot infer an appropriate lifetime due to conflicting requirements" for the functions in a because the lifetimes cannot outlive the while block so that the closures cannot outlive their stack frame, which of course they would because I am invoking them in println!.
I'm sure there must be a way to build up this array of functions, but how?
You need to use move || i.
move implies that this closure will take i by value rather than by reference. By default, these closures would only take references to i. In your case it is forbidden as the lifetime of i is limited to the body of the loop.
Also, Rust will complain that your array may not be fully initialized. To avoid it, you can either use a Vec<_>, or use std::mem::uninitialized:
fn main() {
let mut a: [_; 10] = unsafe { std::mem::uninitialized() };
for i in 0..10 {
a[i] = move || i;
}
println!("{} {} {}", a[1](), a[5](), a[9]())
}
It is possible to collect multiple closures from an iterator into a Vec:
fn main() {
let a: Vec<_> = (0..10).map(|i| move || i).collect();
println!("{} {} {}", a[1](), a[5](), a[9]());
}
The move keyword causes ownership of i to be transferred to the closure.
See also:
How do I collect into an array?
Related
What do the authors mean by the statement "the data representing the object is copied but the object's attributes are not", an someone give me an example of how this works in practice, perhaps in python or java or C?
The following is an excerpt from the first chapter of CLRS algorithms.
"We pass parameters to a procedure by value: the called procedure receives its own copy of the parameters, and if it assigns a value to a parameter, the change is not seen by the calling procedure. When objects are passed, the pointer to the data representing the object is copied, but the object’s attributes are not. For example, if x is a parameter of a called procedure, the assignment x = y within the called procedure is not visible to the calling procedure. The assignment x.f =3, however, is visible. Similarly, arrays are passed by pointer, so that a pointer to the array is passed, rather than the entire array, and changes to individual array elements are visible to the calling procedure"
Thank you in advance for helping me with this problem.
This is the normal behaviour of pretty much all modern imperative programming languages which have immutable primitives and mutable objects, such as Java, Python, Javascript, and so on. I'll use Javascript for examples, but if you don't know Javascript hopefully the code is simple enough that you understand the explanation anyway.
Consider the following code which declares a variable and calls a function:
function foo(x) {
x = 5;
}
var y = 2;
foo(y);
console.log(y); // outputs number 2
The variable x within the function gets its value from y, but is a different variable stored in a different place in memory. So when the function assigns the number 5 to x, the number 5 is not also assigned to y; the change in x is not "visible" outside the function.
Now consider this code, which is essentially the same, just with an object instead of a number:
function bar(x) {
x = { a: 3, b: 4 };
}
var y = { a: 1, b: 2 };
bar(y);
console.log(y); // outputs { a: 1, b: 2 }
Again, x gets its value from y (which is a reference to the object), but assigning a new reference to x doesn't change which reference y holds because they are stored in different memory locations.
Now the final example:
function baz(x) {
x.a = 3;
x.b = 4;
}
var y = { a: 1, b: 2 };
baz(y);
console.log(y); // outputs { a: 3, b: 4 }
This time the function baz does change the result, because y holds a reference to the object, and when the function is called, x holds a reference to the same object (not a copy of the object), so the assignments to its properties are "visible" outside of the function.
If all of this seems straightforward to you, then you can ignore the paragraph; it is simply explaining that the language they use in the book has these behaviours. The purpose of the paragraph is to clarify the semantics of their language, because not all functions in all languages do behave in these ways.
In C++ for example, it is possible to write foo and bar in such a way that they would change the value of y "from a distance". Or, in a functional programming language where objects are immutable, baz wouldn't change the object y, it would instead create new objects with different properties, which wouldn't be visible outside the function.
So this paragraph in their book is a useful clarification for readers who might be more familiar with these other semantics for function parameters.
Please consider the following minimal example in Rust:
const FOOBAR: usize = 3;
trait Foo {
const BAR: usize;
}
struct Fubar();
impl Foo for Fubar {
const BAR: usize = 3;
}
struct Baz<T>(T);
trait Qux {
fn print_bar();
}
impl<T: Foo> Qux for Baz<T> {
fn print_bar() {
println!("bar: {}", T::BAR); // works
println!("{:?}", [T::BAR; 3]); // works
println!("{:?}", [1; FOOBAR]); // works
println!("{:?}", [1; T::BAR]); // this gives an error
}
}
fn main() {
Baz::<Fubar>::print_bar();
}
The compiler gives the following error:
error[E0599]: no associated item named `BAR` found for type `T` in the current scope
--> src/main.rs:24:30
|
24 | println!("{:?}", [1; T::BAR]); // this gives an error
| ^^^^^^ associated item not found in `T`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `BAR`, perhaps you need to implement it:
candidate #1: `Foo`
Whatever the answer to my question, this is not a particularly good error message because it suggests that T does implement Foo despite the latter being a trait bound. Only after burning a lot of time did it occur to me that in fact T::BAR is a perfectly valid expression in other contexts, just not as a length parameter to an array.
What are the rules that govern what kind of expressions can go there? Because arrays are Sized, I completely understand that the length are to be known at compile time. Coming from C++ myself, I would expect some restriction akin to constexpr but I have not come across that in the documentation where it just says
A fixed-size array, denoted [T; N], for the element type, T, and the non-negative compile-time constant size, N.
As of Rust 1.24.1, the array length basically needs to either be a numeric literal or a "regular" constant that is a usize. There's a small amount of constant evaluation that exists today, but it's more-or-less limited to basic math.
a perfectly valid expression in other contexts, just not as a length parameter to an array
Array lengths don't support generic parameters. (#43408)
this is not a particularly good error message
Error message should be improved for associated consts in array lengths (#44168)
I would expect some restriction akin to constexpr
This is essentially the restriction, the problem is that what is allowed to be used in a const is highly restricted at the moment. Notably, these aren't allowed:
functions (except to construct enums or structs)
loops
multiple statements / blocks
Work on good constant / compile-time evaluation is still ongoing. There are a large amount of RFCs, issues, and PRs improving this. A sample:
Const fn tracking issue (RFC 911)
Allow locals and destructuring in const fn (RFC 2341)
Allow if and match in constants (RFC 2342)
This is a minimal example that I struggled to get right.
I am trying to maintain a global Vec<Box<Item>>, the id of the Item is its index. When I want to fetch a reference to the Item, I can always get its id from somewhere, then get a reference by id (as ref_a in the code). But I would prefer directly getting the reference to the Item and pass it around (like ref_b), or even save it somewhere instead of saving the id. But my code doesn't work.
I see that in get_a_certain_item(), the return value &Item would have the same lifetime as VEC.read() thus it is not valid to let the reference escape. However, in my understanding, since all the Items are allocated with boxes in the heap, a reference to it should always be valid. There should be no harm to let the reference live longer than the read guard.
If I am not writing the code right, I guess there should be some idiomatic way to do this in Rust. I would appreciate some help.
// lazy_static = "0.1.15"
#[macro_use]
extern crate lazy_static;
use std::sync::RwLock;
struct Item {
id: usize
}
lazy_static! {
static ref VEC : RwLock<Vec<Box<Item>>> = RwLock::new(vec![
Box::new(Item { id: 0 }),
Box::new(Item { id: 1 }),
Box::new(Item { id: 2 })]);
}
fn get_a_certain_item() -> &Item {
& VEC.read().unwrap()[1]
}
fn get_a_certain_item_by_id() -> usize {
1
}
fn main() {
// this works, but verbose
let ref_a = {& VEC.read().unwrap()[get_a_certain_item_by_id()]};
// this doesn't work
let ref_b = get_a_certain_item();
}
Compiling the code gives this error:
error: missing lifetime specifier [E0106]
fn get_a_certain_item() -> &Item {
^~~~~
help: run `rustc --explain E0106` to see a detailed explanation
help: this function's return type contains a borrowed value,
but there is no value for it to be borrowed from
help: consider giving it a 'static lifetime
In Rust, lifetimes are simply parameterized placeholders, just like generic types (see this answer for more info). That means that every returned reference must have a lifetime that corresponds to some input reference. Your function doesn't have that.
If it were possible for the lifetimes to not correspond, then you'd be able to have code that returned a lifetime that could be whatever the caller wanted it to be. This is generally nonsense, as the reference will stop being valid at some point and thus you'd be breaking the memory safety rules.
What I just said is true, but leaves off one small but important corner case: the 'static lifetime. This is a built-in lifetime that corresponds to items compiled into the code. Normally this means global variables defined with static or references to literal values. These values exist before main is called and are destroyed after main has ended. It is impossible to actually create such values during the runtime of your program.
Note that the error message makes reference to the 'static lifetime. However, if you just add this lifetime, you will get a different error:
error: borrowed value does not live long enough
&VEC.read().unwrap()[1]
^~~~~~~~~~~~~~~~~~~
note: reference must be valid for the static lifetime...
note: ...but borrowed value is only valid for the block at [...]
This is because the compiler cannot ensure that the value will last for the entire length of the program. In fact, it can only ensure it will last for the duration of the function call.
As the programmer, you may know (or think you know) better than the compiler. That's what the unsafe escape hatch is for. This allows you to do things that the compiler cannot verify. It does not allow you to break memory safety; it's just up to the programmer to ensure memory safety instead of the compiler.
In your case, if you can guarantee that items from the vector are never dropped, and that you always use a Box, then it should be safe to pretend that references to the Item are 'static.
A Boxed value is allocated on the heap, and the memory is never moved after the initial creation. Since items in the vector are not dropped, the Box will never be freed.
Here's a verbose example of implementing the method:
fn get_a_certain_item() -> &'static Item {
// Best practice: put a paragraph explaining why this isn't
// actually unsafe.
unsafe {
let as_ref: &Box<Item> = &VEC.read().unwrap()[1];
let as_ref2: &Item = &**as_ref;
let as_raw = as_ref2 as *const _;
let unsafe_ref = &* as_raw;
unsafe_ref
}
}
Converting the reference to a raw pointer throws away the lifetime. When we reconstitute it we can make up whatever lifetime we want.
For what it is worth, I don't think it is worth it in this case. If I actually have a global variable, I want that to be front-and-center in my code as I view it as an ugly wart. I'd much rather create a type that owned a RwLock<Vec<Box<Item>>>, make a global of that type, then parameterize my code to accept a reference to that type. Then I lock the global when I need it and pass the reference into functions.
I can ensure that I won't mutate those elements once they are inserted
You can, can you?
But even if you really really can ensure that the vector will never be mutated, it's still a good practice to use the type system in such a way as to make the illegal states and operations impossible.
In this case, you can hide the Vec in a module, then any user of that module won't be able to mutate the Vec and ruin your invariants.
#[macro_use]
extern crate lazy_static;
// Hides the gory details from the user of the API.
pub mod items {
use std::mem::transmute;
pub struct Item {
pub id: usize
}
lazy_static! {
static ref VEC : Vec<Item> = vec![
Item { id: 0 },
Item { id: 1 },
Item { id: 2 }];
}
pub fn get_an_item (idx: usize) -> Option<&'static Item> {
// As Shepmaster has pointed out, Rust is smart enough to detect
// that the vector is immutable and allow the 'static lifetime:
VEC.get(idx)
// And when it isn't that smart, we can use `unsafe`
// to tell the compiler that the 'static lifetime is okay:
/*
match VEC.get (idx) {
Some (item) => {
// `unsafe` means "safe, scout's honor", cf. http://doc.rust-lang.org/book/unsafe.html
let item: &'static Item = unsafe {transmute (item)};
Some (item)
},
None => None
}
*/
}
}
fn main() {
let ref_b = items::get_an_item (1) .expect ("!1");
assert_eq! (ref_b.id, 1);
}
Note that, since the Vec is immutable, there's no need to Box the Items. This might be nice from the data-driven, cache locality perspective.
And if a user of this module tries for an undefined behavior with a code like this items::VEC.push (items::Item {id: 3}); he'll get an "error: static VEC is private".
Weird title, anyway, in C function parameters are as follows:
void func_name(int a, int b) {
}
However in Rust:
fn func_name(a: int, b: int) {
}
Is this just a preference in syntax and was appealing to the creators of Rust, or is this for a specific purpose that I don't know about? For example, Go has "optional semi-colons", but they are actually to show when an expression ends. Please bare in mind that I'm a complete novice at Rust, so if you try to provide some fancy examples in Rust I probably wont understand :(
The declaration of a function argument is just a special case of variable declarations in Rust, therefore the answer to your question lies in variable declaration in general.
Let us start with C:
a b = 1;
a = 2;
From a grammar point of view, C is not quite regular:
in a b = 1;, a is the type and b is the name of a new variable being declared (and initialized)
in a = 1;, a is the name of a variable that was declared previously and is now either initialized or assigned a new value (overwriting the previous one).
Therefore, in C, knowing whether a is a type or a variable name requires looking ahead (ie, if followed by another variable then it's a type, otherwise it's a variable).
Now, in Rust:
let a = 1;
a = 2;
The syntax for introducing a new variable requires using the let keyword, there is no ambiguity and no need to look ahead to disambiguate. This is all the more important because of shadowing in Rust (let a = ...; let a = a.foo;).
The question was about types though, so let's extend the example:
let a: b = 1;
a = 2;
In this case, again, there is no need to look ahead. Immediately after let comes the variable name, and only after parsing a : comes the variable type.
Therefore, the syntax of Rust is simply meant to avoid look ahead (Rust aims at having a LL(1) syntax) and the syntax of function arguments simply follows the regular syntax.
Oh, and by the way, not all arguments have a type:
impl Foo {
fn doit(&self);
}
In normal Rust code a variable is declared this way:
let x : i32 = 0;
The C style is not possible because the type is optional, so the former is equivalent to this one:
let x = 0i32;
You need the let keyword to declare the intention of declaring a name.
In a function declaration the type is mandatory, the initialization is not allowed and the let keyword makes no sense. Other than that the syntax is the same:
fn foo(x : i32)
It would be weird to have a different syntax for declaring local variables and function arguments, don't you think?
I am constructing an array of booleans to store the state of the sections in a UICollectionView. It is a variable stored as a property of my UIViewController:
var _weekSelections : Array<Bool>!
Then, in a function called by loadView(), I construct the array and assign a value to the first index:
_weekSelections = Array<Bool>(count:_weekCount, repeatedValue:false)
_weekSelections[0] = true
The value at index 0 remains false! The array is constructed, and has multiple elements, but any assignment that I make to an index does not affect the value stored at that index, even if I check the value on the very next line of code. I know that Swift makes a copy of an array if I perform an action that may change its length, but I don't think this is a case where a copy would me made. The only way I can get any value to change is if I manually create a copy as follows:
var copy = _weekSelections
copy[0] = true
_weekSelections = copy
Am I missing something obvious or could this be a strange bug?
For the sake of having my code on SO rather than Pastebin, here's my observation. This looks like some kind of bug or unexpected behaviour when using an optional array in a Swift class derived from an Objective C class. If you use a plain Swift class, this works as expected:
class Foo {
var weekSelections: Array<Bool>!
func test() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "true"
}
}
var foo = Foo()
foo.test()
However, if you derive Foo from NSObject:
import Foundation
class Foo : NSObject { // This derivation is the only difference from the code above
var weekSelections: Array<Bool>!
func test() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "false"
}
}
var foo = Foo()
foo.test()
Even in this case, if you do your weekSelections initialisation in an initialiser, then it works:
class Foo : NSObject {
var weekSelections: Array<Bool>!
init() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "true"
}
}
var foo = Foo()
Personally, I'd say that this is a bug. I can't see anything in any documentation that would explain the difference in behaviour when derived from NSObject.
I also can't see anything that says that optional array properties would be immutable. This would be especially strange when you consider that "immutable" arrays are actually mutable in Swift, i.e. this:
// Use "let" to declare an "immutable" array
let weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]); // Prints "true"; arrays are never really "immutable" in Swift
...works fine, and is currently documented as being valid, even if it seems a bit odd.
Personally, I'd use whatever workaround you can and raise a bug with Apple, to see what light they can shed.
Not an explanation, but a workaround. The issue isn't with the count:repeatedValue initializer, but rather with the array being assigned to an optional variable. From what I can tell optional arrays can only use accessor methods and not mutator methods--effectively they're immutable. Temporarily assigning _weekSelections to a non-optional variable before attempting to change its contents (and assigning back to _weekSelections when done) will work. Please note that this seems to create a new array (with the same elements) on assignments, so there may be memory issues to consider if the array is very big. Of course, simply using a non-optional variable in the first place will also work.
As for why optional arrays aren't mutable, that may be a bug or there may be some esoteric reason for it I'm not fathoming. Anyone else have a plausible-sounding theory?