I want to initialise part of a Datatype in Julia, I currently have:
mutable struct Foo
bar::Int
baz::Int
maz::Int
Foo(maz=2)=new(maz)
end
foo=Foo()
println(foo)
However this creates an object which is Foo(2, 0, 0)
How do I do so that I get Foo(0, 0, 2)
Note: I would prefer to not have to do a complete initialisation
Use new() (see here for details):
julia> mutable struct Foo
bar::Int
baz::Int
maz::Int
function Foo(maz=2)
foo = new()
foo.maz = maz
return foo
end
end
julia> foo=Foo()
Foo(139985835568976, 8, 2)
Note that bar and baz fields are not set to 0 but uninitialized.
Related
I have this code:
struct MyStruct
text::String
function MyStruct(_text::String)
text = _text
# do other things
end
end
When I wrote this, I realized that Julia is not recognizing text as MyStruct's field. How can I do something like this in Julia like in Python?
self.text = _text
Don't try to imitate Python. Julia is not object oriented.
You could emulate a Python-style constructor by
mutable struct MyStruct
text::String
function MyStruct(text::String)
self = new()
self.text = some_stuff(text)
return self
end
end
but for this to work the struct needs to be mutable. Then you can set up an uninitialize instance with new() and overwrite the fields.
Note that this is more equivalent to a combination of both __init__ and __new__. In Python, the new part is (99% of the time) already done for you, and you just mutate the already created empty object in __init__. In Julia, you have to do both on your own; this especially also requires returning the new value at the end of the constructor!
Having said all this, it's not often useful to write that way. More idiomatic would be just
struct MyStruct
text::String
MyStruct(text::String) = new(some_stuff(text))
end
unless you absolutely need the struct to be mutable (which has consequences with respect to memory layout and possible optimizations).
And also read up on the difference between inner and outer constructors. If you want the above to be the only valid way to construct MyStruct, this is fine. If you want "convenience constructors", e.g. with default arguments or conversions from other types, prefer outer constructors (where you don't have new but recursively call constructors until an inner constructor is reached).
Taking a quick glance at the constructors documentation and trying out the playground, I was able to come up with this:
struct MyStruct
text::String
function MyStruct(_text::String)
s = new(_text * "def")
# do other things
s
end
end
s = MyStruct("abc")
println(s.text) # abcdef
Why does the following code work?
use std::rc::Rc;
fn main () {
let c = vec![1, 2, 3, 4, 5];
let r = Rc::new(c);
println!("{:?}", (**r)[0]);
}
I can understand it working with single deference (println!("{:?}", (*r)[0]);). But not able to understand it working with double-dereference too.
Both, Rc and Vec implements Deref, whichs deref-method is called with the *.
let c = vec![1, 2, 3, 4, 5];
creates a Vec with the given elements with the vec!-macro.
let r = Rc::new(c);
creates a Reference counted Object from the Vector. The Vector is moved into the RC.
println!("{:?}", (**r)[0]);
This one is a bit more tricky: *r dereferences the Rc, so we get the underlying Vector. *rc dereferences the Vector as a slice. slice[0] indexes the first element of the slice, which results in the first element 1. println! finally prints the result.
It might be easier to understand what happens once we build a function prototype around the expression (**r)[0]:
fn foo<T, U>(r: T) -> i32
where
T: Deref<Target=U>,
U: Deref<Target=[i32]>,
{
(**r)[0]
}
Playground
Rc<T>, as is typical for most smart containers in Rust, implements Deref so that it can be used as an ordinary reference to the underlying value. In turn, Vec<T> implements Deref so that it can be used as a slice (Target = [T]). The explicit dereferencing *, when performed twice, applies the two conversions in sequence.
Of course, usually you wouldn't need to do this, because Vec also implements the Index operator.
I have a boxed array of structs and I want to consume this array and insert it into a vector.
My current approach would be to convert the array into a vector, but the corresponding library function does not seem to work the way I expected.
let foo = Box::new([1, 2, 3, 4]);
let bar = foo.into_vec();
The compiler error states
no method named into_vec found for type Box<[_; 4]> in the current scope
I've found specifications here that look like
fn into_vec(self: Box<[T]>) -> Vec<T>
Converts self into a vector without clones or allocation.
... but I am not quite sure how to apply it. Any suggestions?
I think there's more cleaner way to do it. When you initialize foo, add type to it. Playground
fn main() {
let foo: Box<[u32]> = Box::new([1, 2, 3, 4]);
let bar = foo.into_vec();
println!("{:?}", bar);
}
The documentation you link to is for slices, i.e., [T], while what you have is an array of length 4: [T; 4].
You can, however, simply convert those, since an array of length 4 kinda is a slice. This works:
let foo = Box::new([1, 2, 3, 4]);
let bar = (foo as Box<[_]>).into_vec();
I'm using a newtype, wrapping an array of integers:
struct Foo([int, ..5]);
Since, apparently, I cannot simply do this:
let foo = Foo([1,2,3,4,5]);
let bar = foo[2];
How exacty do I access the wrapped array?
There are one-and-a-half (soon to be two) ways:
#![feature(tuple_indexing)]
struct Foo([int, ..5]);
fn main() {
let foo = Foo([1,2,3,4,5]);
let Foo([_, foo_1, ..]) = foo;
let foo_3 = foo.0[3];
println!("[_, {}, _, {}, _]", foo_1, foo_3);
}
Specifically, tuple_indexing is likely to be un-gated soon, so you won't need the feature attribute to use it.
Basically, Foo is a tuple struct; that is, it behaves more or less just like a tuple that happens to have a name.
Editor's note: The code in this question predates Rust 1.0. The equivalent modern version of this code compiles as-is.
I'm still taking baby steps at learning Rust, and was surprised at the following.
I couldn't understand why this code compiles:
use std::iter::AdditiveIterator;
fn main() {
let range = [1,2,3,4,5,6,7,8,9];
let sum = range.iter().map(|&x| x * x).filter(|&x| x % 2 == 0).sum();
println!("{}", sum);
}
While this doesn't: (just moving the .iter() up)
use std::iter::AdditiveIterator;
fn main() {
let range = [1,2,3,4,5,6,7,8,9].iter();
let sum = range.map(|&x| x * x).filter(|&x| x % 2 == 0).sum();
println!("{}", sum);
}
Which renders this error:
test.rs:5:17: 5:36 error: borrowed value does not live long enough
test.rs:5 let range = [1,2,3,4,5,6,7,8,9].iter();
^~~~~~~~~~~~~~~~~~~
I'm sure it has something to do with Rust scopes etc, but I'm not sure I understand how by just moving the method call to a different line makes a difference.
The array gets destroyed at the end of the let range = [1,2,3,4,5,6,7,8,9].iter(); statement as there is no variable that holds that vector. This would cause a dangling iterator pointing nowhere.
The same occurs in C++, where it is possible to create iterator on object that gets deleted after.
In modern Rust, the equivalent code compiles:
fn main() {
let range = [1, 2, 3, 4, 5, 6, 7, 8, 9].iter();
let sum: i32 = range.map(|&x| x * x).filter(|&x| x % 2 == 0).sum();
println!("{}", sum);
}
This is because literals, like the array literal, are now automatically promoted to static variables if they need to be. The result of iter here is now a std::slice::Iter<'static, i32>.
See also:
Why can I return a reference to a local literal but not a variable?