Rust impl default trait with private fields - rust

I'm getting an error when I have this sort of setup:
default_test.rs:
mod default_mod;
use default_mod::Point;
fn main() {
let _p1 = Point::new();
let _p2: Point = Point {
z: 1,
..Default::default()
};
}
default_mod.rs:
pub struct Point {
x: i32,
y: i32,
pub z: i32,
}
impl Point {
pub fn new() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
impl Default for Point {
fn default() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
which gives the compiler error:
default_test.rs:9:7
|
9 | ..Default::default()
| ^^^^^^^^^^^^^^^^^^ field `x` is private
error[E0451]: field `y` of struct `default_mod::Point` is private
Short version - I have a struct with both public and private fields. I would like to initialise this struct with default values, but sometimes override them.
I can't seem to fix this error, nor seen anything on the internet or the docs that even mentions errors like this.
It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
In my case the private field is a Vec as I have some logic that needs to go into adding or removing things from the vector, so I want to make it private to prevent anyone messing up the data structure.
What are my options here?

It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
The problem is that the struct update syntax doesn't do what you think it does. For example, the book shows the following code:
let user2 = User {
email: String::from("another#example.com"),
username: String::from("anotherusername567"),
..user1
};
The ..user1 syntax fills in the User fields we haven't explicitly specified, such as active: user1.active, signin_count: user1.signin_count. .. may be followed by an arbitrary expression which returns the structure, which is where Default::default() comes into play, and means the same as User::default() because a User is expected. However, the desugaring remains unchanged and boils down to assigning individual fields, in neither case granting special access to private fields.
To get back to your example, this code:
let p = Point {
z: 1,
..Default::default()
};
is syntactic sugar for:
let p = {
let _tmp = Point::default();
Point {
x: _tmp.x,
y: _tmp.y,
z: 1,
}
};
and not for the expected:
// NOT what happens
let p = {
let _tmp = Point::default();
p.z = 1;
_tmp
};
What are my options here?
The most idiomatic option is to provide a builder for Point. That is also somewhat bulky1, so if you're looking for a simple solution, you could also use Point::default() and set the z attribute manually. The struct update syntax is incompatible with structs with private fields and just not useful for your type.
1
Though there are crates like derive_builder, typed-builder and builder-pattern that take some of the drudgery away.

What are my options here?
A new() with parameters or a builder.
..struct is just a convenient way of doing functional updates, it doesn't bypass ACLs. Here since your struct has private fields, users can not manipulate it as a "bare" struct, they have to treat it as a largely opaque type.

Related

Binary tree node with pointer to siblings in Rust

I am trying to figure out the equivalent of the typical setSibling C code exercise:
// Assume the tree is fully balanced, i.e. the lowest level is fully populated.
struct Node {
Node * left;
Node * right;
Node * sibling;
}
void setSibling(Node * root) {
if (!root) return;
if (root->left) {
root->left->sibling = root->right;
if (root->sibling) root->right->sibling = root->sibling->left;
SetSibling(left);
SetSibling(right);
}
}
Of course Rust is a different world, so I am forced to think about ownership now. My lousy attempt.
struct TreeNode<'a> {
left: Option<&'a TreeNode<'a>>,
right: Option<&'a TreeNode<'a>>,
sibling: Option<&'a TreeNode<'a>>,
value: String
}
fn BuildTreeNode<'a>(aLeft: Option<&'a TreeNode<'a>>, aRight: Option<&'a TreeNode<'a>>, aValue: String) -> TreeNode<'a> {
TreeNode {
left: aLeft,
right: aRight,
value: aValue,
sibling: None
}
}
fn SetSibling(node: &mut Option<&TreeNode>) {
match node {
Some(mut n) => {
match n.left {
Some(mut c) => {
//c*.sibling = n.right;
match n.sibling {
Some(s) => { n.right.unwrap().sibling = s.left },
None => {}
}
},
None => {}
}
},
None => return
}
}
What's the canonical way to represent graph nodes like these?
Question: what's the canonical way to represent graph nodes like these?
It seems like a typical case of "confused ownership" once you introduce the sibling link: with a strict tree you can have each parent own its children, but the sibling link means this is a graph, and a given node has multiple owners.
AFAIK there are two main ways to resolve this, at least in safe Rust
reference counting and inner mutability, if each node is reference-counted, the sibling link can be a reference or weak reference with little trouble, the main drawbacks are this requires inner mutability and the navigation is gnarly, though a few utility methods can help
"unfold" the graph into an array, and use indices for your indirection through the tree, the main drawback is this requires either threading or keeping a backreference (with inner mutability) to the array, or alternatively doing everything iteratively
Both basically work around the ownership constraint, one by muddying the ownership itself, and the other by moving ownership to a higher power (the array).
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=68d092d0d86dc32fe07902c832262ef4 seems to be more or less what you're looking using Rc & inner mutability:
use std::cell::RefCell;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub struct TreeNode {
left: Option<Rc<TreeNode>>,
right: Option<Rc<TreeNode>>,
sibling: RefCell<Option<Weak<TreeNode>>>,
v: u8,
}
impl TreeNode {
pub fn new(v: u8) -> Rc<Self> {
Rc::new(TreeNode {
v,
..TreeNode::default()
})
}
pub fn new_with(left: Option<Rc<TreeNode>>, right: Option<Rc<TreeNode>>, v: u8) -> Rc<Self> {
Rc::new(TreeNode {
left,
right,
v,
sibling: RefCell::new(None),
})
}
pub fn set_siblings(self: &Rc<Self>) {
let Some(left) = self.left() else { return };
let right = self.right();
left.sibling.replace(right.map(Rc::downgrade));
if let Some(sibling) = self.sibling() {
// not sure this is correct, depending on construction, with
// 3 5
// \ \
// 2 4
// \/
// 1
// (2) has a sibling (4) but doesn't have a right node, so
// unconditionally setting right.sibling doesn't seem correct
right
.unwrap()
.sibling
.replace(sibling.left().map(Rc::downgrade));
}
left.set_siblings();
right.map(|r| r.set_siblings());
}
pub fn left(&self) -> Option<&Rc<Self>> {
self.left.as_ref()
}
pub fn right(&self) -> Option<&Rc<Self>> {
self.right.as_ref()
}
pub fn sibling(&self) -> Option<Rc<Self>> {
self.sibling.borrow().as_ref()?.upgrade()
}
}
fn main() {
let t = TreeNode::new_with(
TreeNode::new_with(TreeNode::new(1).into(), TreeNode::new(2).into(), 3).into(),
TreeNode::new(4).into(),
5,
);
t.set_siblings();
assert_eq!(t.left().and_then(|l| l.sibling()).unwrap().v, 4);
let ll = t.left().and_then(|l| l.left());
assert_eq!(ll.map(|ll| ll.v), Some(1));
ll.unwrap().sibling().unwrap();
assert_eq!(
t.left()
.and_then(|l| l.left())
.and_then(|ll| ll.sibling())
.unwrap()
.v,
2
);
}
Note that I assumed the tree is immutable once created, only the siblings links have to be generated post-facto. So I only added inner mutability for those. I also used weak pointers which probably isn't necessary, if the tree is put in an inconsistent state it's not like that'll save anything. All it requires is a few upgrade() and downgrade() calls in stead of clone() though so it's not a huge imposition.
That aside, there are lots of issues with your attempt:
having the same lifetime for your reference and your content is usually an error, the compiler will trust what you tell it, and that can have rather odd effects (e.g. of telling the compiler that something gets borrowed forever)
SetSibling (incorrect naming conventions btw) taking an Option is... unnecessary, function clearly expects to set a sibling, just give it a sibling, and remove the unnecessary outer layer of tests
match is nice, when you need it. Here, you probably don't, if let would do the trick fine especially since there is no else branch
rust generally uses methods, and the method to create an instance (if one such is needed) is idiomatically called new (if there's only one)

How can I make struct variables inaccessible to change from default value when using default initialization? [duplicate]

I'm getting an error when I have this sort of setup:
default_test.rs:
mod default_mod;
use default_mod::Point;
fn main() {
let _p1 = Point::new();
let _p2: Point = Point {
z: 1,
..Default::default()
};
}
default_mod.rs:
pub struct Point {
x: i32,
y: i32,
pub z: i32,
}
impl Point {
pub fn new() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
impl Default for Point {
fn default() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
which gives the compiler error:
default_test.rs:9:7
|
9 | ..Default::default()
| ^^^^^^^^^^^^^^^^^^ field `x` is private
error[E0451]: field `y` of struct `default_mod::Point` is private
Short version - I have a struct with both public and private fields. I would like to initialise this struct with default values, but sometimes override them.
I can't seem to fix this error, nor seen anything on the internet or the docs that even mentions errors like this.
It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
In my case the private field is a Vec as I have some logic that needs to go into adding or removing things from the vector, so I want to make it private to prevent anyone messing up the data structure.
What are my options here?
It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
The problem is that the struct update syntax doesn't do what you think it does. For example, the book shows the following code:
let user2 = User {
email: String::from("another#example.com"),
username: String::from("anotherusername567"),
..user1
};
The ..user1 syntax fills in the User fields we haven't explicitly specified, such as active: user1.active, signin_count: user1.signin_count. .. may be followed by an arbitrary expression which returns the structure, which is where Default::default() comes into play, and means the same as User::default() because a User is expected. However, the desugaring remains unchanged and boils down to assigning individual fields, in neither case granting special access to private fields.
To get back to your example, this code:
let p = Point {
z: 1,
..Default::default()
};
is syntactic sugar for:
let p = {
let _tmp = Point::default();
Point {
x: _tmp.x,
y: _tmp.y,
z: 1,
}
};
and not for the expected:
// NOT what happens
let p = {
let _tmp = Point::default();
p.z = 1;
_tmp
};
What are my options here?
The most idiomatic option is to provide a builder for Point. That is also somewhat bulky1, so if you're looking for a simple solution, you could also use Point::default() and set the z attribute manually. The struct update syntax is incompatible with structs with private fields and just not useful for your type.
1
Though there are crates like derive_builder, typed-builder and builder-pattern that take some of the drudgery away.
What are my options here?
A new() with parameters or a builder.
..struct is just a convenient way of doing functional updates, it doesn't bypass ACLs. Here since your struct has private fields, users can not manipulate it as a "bare" struct, they have to treat it as a largely opaque type.

What is the ".." syntax inside a struct literal in Rust?

From the std::default::Default docs:
#[derive(Default)]
struct SomeOptions {
foo: i32,
bar: f32,
}
fn main() {
let options = SomeOptions { foo: 42, ..Default::default() };
}
What is the .. prefix doing to the returned value of Default::default() and why is it necessary here? It almost seems like it's acting as a spread operator, but I'm not sure. I understand what ..Default::default() is doing -- filling in the remaining struct parameters with the default values of SomeOptions, but not how .. works. What is the name of this operator?
This is the struct update syntax. It is "needed" only to have a succinct way of moving / copying all of the members of a struct to a new one, potentially with some small modifications.
The "long" way of writing this would be:
let a = SomeOptions::default();
let options = SomeOptions { foo: 42, bar: a.bar };
You could indeed think of it similar to the JavaScript "spread" operator, but Rust's nuances of ownership and strong typing still come into play, so it's not as widely used. For example, you can't use this syntax to go between values of different types.

Can't figure out a function to return a reference to a given type stored in RefCell<Box<Any>>

Most of this is boilerplate, provided as a compilable example. Scroll down.
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::any::{Any, AnyRefExt};
struct Shared {
example: int,
}
struct Widget {
parent: Option<Weak<Box<Widget>>>,
specific: RefCell<Box<Any>>,
shared: RefCell<Shared>,
}
impl Widget {
fn new(specific: Box<Any>,
parent: Option<Rc<Box<Widget>>>) -> Rc<Box<Widget>> {
let parent_option = match parent {
Some(parent) => Some(parent.downgrade()),
None => None,
};
let shared = Shared{pos: 10};
Rc::new(box Widget{
parent: parent_option,
specific: RefCell::new(specific),
shared: RefCell::new(shared)})
}
}
struct Woo {
foo: int,
}
impl Woo {
fn new() -> Box<Any> {
box Woo{foo: 10} as Box<Any>
}
}
fn main() {
let widget = Widget::new(Woo::new(), None);
{
// This is a lot of work...
let cell_borrow = widget.specific.borrow();
let woo = cell_borrow.downcast_ref::<Woo>().unwrap();
println!("{}", woo.foo);
}
// Can the above be made into a function?
// let woo = widget.get_specific::<Woo>();
}
I'm learning Rust and trying to figure out some workable way of doing a widget hierarchy. The above basically does what I need, but it is a bit cumbersome. Especially vexing is the fact that I have to use two statements to convert the inner widget (specific member of Widget). I tried several ways of writing a function that does it all, but the amount of reference and lifetime wizardry is just beyond me.
Can it be done? Can the commented out method at the bottom of my example code be made into reality?
Comments regarding better ways of doing this entire thing are appreciated, but put it in the comments section (or create a new question and link it)
I'll just present a working simplified and more idiomatic version of your code and then explain all the changed I made there:
use std::rc::{Rc, Weak};
use std::any::{Any, AnyRefExt};
struct Shared {
example: int,
}
struct Widget {
parent: Option<Weak<Widget>>,
specific: Box<Any>,
shared: Shared,
}
impl Widget {
fn new(specific: Box<Any>, parent: Option<Rc<Widget>>) -> Widget {
let parent_option = match parent {
Some(parent) => Some(parent.downgrade()),
None => None,
};
let shared = Shared { example: 10 };
Widget{
parent: parent_option,
specific: specific,
shared: shared
}
}
fn get_specific<T: 'static>(&self) -> Option<&T> {
self.specific.downcast_ref::<T>()
}
}
struct Woo {
foo: int,
}
impl Woo {
fn new() -> Woo {
Woo { foo: 10 }
}
}
fn main() {
let widget = Widget::new(box Woo::new() as Box<Any>, None);
let specific = widget.get_specific::<Woo>().unwrap();
println!("{}", specific.foo);
}
First of all, there are needless RefCells inside your structure. RefCells are needed very rarely - only when you need to mutate internal state of an object using only & reference (instead of &mut). This is useful tool for implementing abstractions, but it is almost never needed in application code. Because it is not clear from your code that you really need it, I assume that it was used mistakingly and can be removed.
Next, Rc<Box<Something>> when Something is a struct (like in your case where Something = Widget) is redundant. Putting an owned box into a reference-counted box is just an unnecessary double indirection and allocation. Plain Rc<Widget> is the correct way to express this thing. When dynamically sized types land, it will be also true for trait objects.
Finally, you should try to always return unboxed values. Returning Rc<Box<Widget>> (or even Rc<Widget>) is unnecessary limiting for the callers of your code. You can go from Widget to Rc<Widget> easily, but not the other way around. Rust optimizes by-value returns automatically; if your callers need Rc<Widget> they can box the return value themselves:
let rc_w = box(RC) Widget::new(...);
Same thing is also true for Box<Any> returned by Woo::new().
You can see that in the absence of RefCells your get_specific() method can be implemented very easily. However, you really can't do it with RefCell because RefCell uses RAII for dynamic borrow checks, so you can't return a reference to its internals from a method. You'll have to return core::cell::Refs, and your callers will need to downcast_ref() themselves. This is just another reason to use RefCells sparingly.

Build object with specific lifetime

I have a problem that I don't know exactly how to model into Rust, in regard with ownership, lifetime and all that.
I have a large struct:
struct LargeStruct {
x: f32,
n: i32,
// lot of other fields.
}
The struct being large, I want to avoid copies, and therefore I carry around pointers to it.
I have a foo function that takes a pointer to LargeStruct and a f32 value. If this value is larger than the field x, I want to create a new object with x set to this value, and returns it. If it is not larger, then I want to return the original pointer itself.
I naively implemented it like this:
fn foo(object: &LargeStruct, y: f32) -> &LargeStruct {
if object.x < y {
LargeStruct {
x: y,
n: object.n,
// ...
}
}
else {
object
}
}
But it does not work: the two branches of the if do no return the same type. In the first case, I actually return a LargeStruct, and in the second I return a &LargeStruct. If I modify the object construction to take its pointer:
&LargeStruct {
then it doesn't work either: the lifetime of the object constructed is too short, so I can not return that from the function.
If I try to build the object on the heap:
~LargeStruct {
I have now another compilation error:
if and else have incompatible types: expected ~LargeStruct but found
&LargeStruct (expected &-ptr but found ~-ptr)
I tried to specify a lifetime in the function signature:
fn foo<'a>(object: &'a LargeStruct, y: f32) -> &'a LargeStruct {
But it does not help: I don't know how to build a new LargeStruct with the same lifetime.
I am calling this function like this:
fn main() {
let object = LargeStruct{
x: 1.0,
n: 2,
// ...
};
let result = foo(&object, 2.0);
}
The intent behind your approach is to only return a modified copy under certain conditions if I understand it right. In Rust this can be modeled with a function that returns an Option<~LargeStruct> type (perhaps even with Option<LargeStruct> but I'm not sure if the compiler can efficiently move large objects in this case).
fn foo(object: &LargeStruct, y: f32) -> Option<~LargeStruct> {
if object.x < y {
return Some(~LargeStruct {
x: y,
//n: object.n,
// ...
})
}
None
}
As for why your approach didn't work: Rust doesn't let you return a reference to an object that will be freed once the function returns. A lifetime is a way to say that an object must live at least as long as the references to it.
The answer to the question as asked
It is not possible to design something in this way with it completely transparent; a reference must always have a lifetime not in excess of the scope of its owner; it is thus impossible to return a reference to an object whose scope does not exceed the function.
This can be solved in a way with an enum specifying the return type as either a reference to a LargeStruct or a LargeStruct, but it's clumsy:
pub struct LargeStruct {
a: int,
}
pub enum LargeStructOrRef<'a> {
LargeStructRef(&'a LargeStruct),
LargeStruct(LargeStruct),
}
fn foo<'a>(object: &'a LargeStruct, y: f32) -> LargeStructOrRef<'a> {
if object.x < y {
LargeStruct(LargeStruct {
x: y,
n: object.n,
// ...
})
} else {
LargeStructRef(object)
}
}
You'd then need to do pattern matching between LargeStruct and LargeStructRef—it can't be made transparent to the caller.
Alternative designs
You can probably design this in a different way which will resolve these difficulties. For example, you might make foo take a &mut LargeStruct and modify the struct rather than creating a new one if object.x < y. (This is most likely to be the design you actually want, I think.)

Resources