Accessing private fields from different modules - rust

mod root {
mod foo {
pub struct Foo {
i: i32,
}
}
mod bar {
pub struct Bar {
f: ::root::foo::Foo,
}
impl Bar {
pub fn new(i: i32) -> Self {
Bar { f: ::root::foo::Foo { i: i } }
}
}
}
}
fn main() {}
playground
The user should be able to interact with Foo, but the user should not be able to construct it manually because it is unsafe.
The module bar should still be able to construct Foo. As far as I know the only way to do this is to put Foo inside the root module or inside the bar module.
Is there a cleaner way to solve this problem? I named the modules here foo and bar but in my code they are separate files like foo.rs bar.rs. Is possible to put foo.rs bar.rs into the same module so that they can see the private fields but still be live in separate files?
My current workaround was to expose a public unsafe new method for Foo.

I think I found a better workaround
pub mod root {
use self::foo::create_foo;
mod foo {
pub struct Foo {
i: i32,
}
impl Foo{
pub fn hello_foo(&self){
println!("Hello foo");
}
}
pub fn create_foo(i: i32) -> Foo{
Foo { i: i }
}
}
pub mod bar {
pub struct Bar {
pub f: ::root::foo::Foo,
}
impl Bar {
pub fn new(i: i32) -> Self {
Bar { f: ::root::foo::create_foo(i) }
}
}
}
}
fn main() {
//still private
//let f = root::foo::create_foo(42);
let b = root::bar::Bar::new(42);
b.f.hello_foo();
}
playground
I expose a public constructor create_foo in foo but the module foo still remains private and I only expose create_foo in root which means that bar can now create a Foo but create_foo is still private outside of root.

Related

Why can I write Guess{value:1000} when value is private?

I have a code like this from the offical tutorial book Chapter 9.3
#![allow(unused)]
fn main() {
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
let g = Guess{
value:1000
};
println!("{}", g.value);
}
According to the book I should not be able to create a Guess using the let g = Guess {} However, this code does not cause any error and prints 1000
There is still a problem even if I put the struct and impl outside the main func like this and delete the pub keyword.
struct Guess {}
impl Guess {}
fn main() {}
According to the book I should not be able to create a Guess using the let g = Guess {}
It is unlikely that the book states that.
Rust visibility works in terms of modules, anything in a module can see all the contents of their parents regardless of their pub status; the reverse is not true.
Since main and Guess.value are in the same module, there is no barrier. Moving Guess out of main doesn't change that, they're still in the same module. For visibility to become an issue, Guess needs to be moved into a separate non-ancestor module (e.g. a sub-module, or a sibling).
Example:
pub struct Foo(usize);
pub mod x {
pub struct Bar(usize);
impl Bar {
pub fn get(&self) -> usize { self.0 }
}
pub fn make(n: super::Foo) -> Bar {
// can access Foo's fields because this is a
// descendant module, so it is "part of" the
// same module
Bar(n.0)
}
}
pub fn qux(n: x::Bar) -> Foo {
// Can't access Bar's field because it's not exposed to this module
// Foo(n.0)
Foo(n.get())
}

How to write a generic function in Rust that can accept any struct that implements a specific property?

I am trying to understand generics in Rust and have attempted to write a generic function that can multiple any struct that has the property foo by 10. When I use this code, I get the error, no field foo on type T.
struct A {
foo: i8,
bar: String,
}
struct B {
foo: i8,
}
fn go<T>(v: T) {
v.foo * 10
}
fn main() {
let a = A {foo: 1, bar: "bar".to_string()};
let b = B {foo: 2};
println!("{:?},{:?}", go(a), go(b))
}
How can I write a generic function that can accept any struct that implements a foo: i8 property?
Rust doesn't have properties in the way that JavaScript does, so you need to do things a little differently. You'll want to use a trait to expose the foo functionality as a method, and then implement that trait for A and B:
trait Foo {
fn foo(&self) -> i8;
}
struct A {
foo: i8,
bar: String,
}
impl Foo for A {
fn foo(&self) -> i8 {
self.foo
}
}
struct B {
foo: i8,
}
impl Foo for B {
fn foo(&self) -> i8 {
self.foo
}
}
fn go<T: Foo>(v: T) -> i8 {
v.foo() * 10
}
fn main() {
let a = A {
foo: 1,
bar: "bar".to_string(),
};
let b = B { foo: 2 };
println!("{:?},{:?}", go(a), go(b))
}
(Note that I also made go return a value above.)
This provides a Foo trait that exposes foo as a method, implements it for A and B, and then makes go require T to implement Foo. That's the easiest and most straightforward way to accomplish this goal.

Turn an upstream struct into a trait

I've got to interact with some upstream code that exposes an interface that could be a trait but is instead implemented directly on a struct. I'd like to pull out that interface into a trait so that my code can support alternative implementations. This can in fact be done, but isn't particularly ergonomic:
pub mod upstream_code {
pub struct Foo(());
impl Foo {
pub fn foo(&self) -> &'static str {
"foo"
}
}
impl Default for Foo {
fn default() -> Self {
Foo(())
}
}
}
mod my_code {
pub trait Foo {
fn foo(&self) -> &'static str;
}
impl Foo for super::upstream_code::Foo {
fn foo(&self) -> &'static str {
self.foo()
}
}
pub fn do_something<T: Foo>(t: T) {
println!("foo: {}", t.foo());
}
}
fn main() {
my_code::do_something(upstream_code::Foo::default());
}
Specifically, note that I have to regurgitate each function in wrapper form inside the impl Foo for super::upstream_code::Foo block.
There's Got To Be A Better Way! What's the most idiomatic way of handling this?

Is it possible to make a private variable in Rust?

I'm trying to generate prime numbers. The code needs to store all the generated primes (to generate the next), to have some private functions to help and one public function (generate_next_prime).
In Java or C++, I would write a PrimesGen class, but in Rust there can't be private variables in a struct. In Python I would probably write a PrimesGen module, but in Rust modules can't have variables.
This code compiles and runs:
struct PrimesGen {
primes_so_far: Vec<i32>,
next_candidate: i32,
}
impl PrimesGen {
pub fn new() -> PrimesGen {
PrimesGen {
primes_so_far: vec![],
next_candidate: 2,
}
}
}
fn main() {
let pg: PrimesGen = PrimesGen::new();
println!("{}", pg.next_candidate);
}
So what do I do?
In Rust, a file is implicitly a module. When you put some code in a foo.rs file, if you want to use this code, you must type mod foo; because the name of this file is implicitly the name of the module. The file with the main is not an exception: it is one module (the base module).
Now, inside a module, everything has access to everything. See this little example to be convinced:
struct Foo {
x: i32, // private
}
struct Bar {}
impl Bar {
fn foo(f: Foo) {
let _ = f.x;
}
}
fn main() {
let f = Foo { x: 42 };
Bar::foo(f);
}
Bar can access the private members of Foo: in Rust, the visibility works by module, and not struct. Inside a same module you cannot do something private towards the same module.
So, if you want to make the variable private in your example, put your struct and implementation inside a module:
mod prime {
pub struct PrimesGen {
primes_so_far: Vec<i32>,
next_candidate: i32,
}
impl PrimesGen {
pub fn new() -> PrimesGen {
PrimesGen {
primes_so_far: vec![],
next_candidate: 2,
}
}
}
}
fn main() {
use prime::*;
let pg: PrimesGen = PrimesGen::new();
println!("{}", pg.next_candidate); // error: field is private
}

Implementing Rust traits cause struct to not be found

When I implement a trait on a struct in Rust it's causing the struct type not to be found. First, the working code:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeStruct {
fn new() -> Box<SomeStruct> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
Here the SomeTrait trait isn't being used. Everything works. If I now change the impl of SomeStruct to implement SomeTrait:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeTrait for SomeStruct {
fn new() -> Box<SomeTrait> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
I get the error:
trait.rs:21:13: 21:28 error: failed to resolve. Use of undeclared module `SomeStruct`
trait.rs:21 let obj = SomeStruct::new();
^~~~~~~~~~~~~~~
trait.rs:21:13: 21:28 error: unresolved name `SomeStruct::new`.
trait.rs:21 let obj = SomeStruct::new();
What am I doing wrong? Why is SomeStruct suddenly missing? Thanks!
At the moment, associated functions (non-method functions) in traits are called via the trait, i.e. SomeTrait::new(). However, if you just write this, the compiler cannot work out which impl you're using, as there's no way to specify the SomeStruct information (it only works if the special Self type is mentioned in the signature somewhere). That is, the compiler needs to be able to work out which version of new should be called. (And this is required; they could have very different behaviour:
struct Foo;
impl SomeTrait for Foo {
fn new() -> Box<SomeTrait> { box Foo as Box<SomeTrait> }
}
struct Bar;
impl SomeTrait for Bar {
fn new() -> Box<SomeTrait> {
println!("hello")
box Bar as Box<SomeTrait>
}
}
Or something more dramatic than just printing.)
This is a language hole that will be filled by UFCS. For the moment, you need to use the dummy-Self trick:
trait SomeTrait {
fn new(_dummy: Option<Self>) -> Box<SomeTrait>;
...
}
which is then called like SomeTrait::new(None::<SomeStruct>).
However, I question why you are returning a boxed object from a constructor. This is rarely a good idea, it's normally better to just return the plain type directly, and the user can box it if necessary, that is,
trait SomeTrait {
fn new() -> Self;
...
}
(NB. this signature mentions Self and thus the Option trick above isn't required.)
Sidenote: the error message is rather bad, but it just reflects how these methods are implemented; an associated function in an impl Foo is very similar to writing mod Foo { fn ... }. You can see it differ by forcing the compiler to create that module:
struct Foo;
impl Foo {
fn bar() {}
}
fn main() {
Foo::baz();
}
prints just
<anon>:7:5: 7:13 error: unresolved name `Foo::baz`.
<anon>:7 Foo::baz();
^~~~~~~~
i.e. the Foo "module" exists.

Resources