Can't understand Rust module system - module

I created a simple project for educational purpose, so I have a main function and 3 traits Battery, Display and GSM and implementations for them. I want the the main function to be in file main.rs and the 3 traits in another file called phone.rs:
phone.rs
mod phone{
pub struct Battery{
model : String,
hours_idle : i16,
hours_talk : i16
}
pub struct Display{
size : i16,
number_of_colors : i32
}
pub struct GSM{
model : String,
manufactor : String,
price : f32,
owner : String,
battery: Battery,
display : Display
}
impl Battery {
pub fn new(model : String, hours_idle : i16, hours_talk : i16) -> Battery{
Battery {model : model, hours_idle : hours_idle ,hours_talk : hours_talk}
}
pub fn print(&self){
println!("Battery model: {}", self.model);
println!("Hours idle: {}", self.hours_idle);
println!("hours talk: {}", self.hours_talk);
}
}
impl Display {
pub fn new(size: i16, number_of_colors : i32) -> Display{
Display{size : size, number_of_colors : number_of_colors}
}
pub fn print(&self){
println!("size: {}", self.size);
println!("number_of_colors: {}", self.number_of_colors);
}
}
impl GSM {
pub fn new(model : String, manufactor : String, price : f32, owner : String, battery : Battery, display : Display) -> GSM{
GSM{model : model, manufactor : manufactor, price : price, owner : owner, battery : battery, display : display }
}
pub fn print(&self){
println!("Model: {}, Manufactor: {}", self.model, self.manufactor);
println!("price: {}", self.price);
println!("owner: {}", self.owner);
self.battery.print();
self.display.print();
}
}
}
main.rs
pub mod phone;
fn main(){
let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
let display = phone::Display::new(10,20);
//model : String, manufactor : String, price : f32, owner : String, baterry : Battery, display : Display
let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
gsm.print();
}
At first, everything was in one file (main.rs) and everything worked fine (there was some difference for example I added phone:: in front of Display, GSM and Battery in main.rs), when I moved the traits and added mod phone{} in phone.rs, and pub mod phone in main.rs, I got the following errors from the compiler:
src\main.rs:3:18: 3:37 error: failed to resolve. Could not find `Battery` in `phone` [E0433]
src\main.rs:3 let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
^~~~~~~~~~~~~~~~~~~
src\main.rs:3:18: 3:37 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:3:18: 3:37 error: unresolved name `phone::Battery::new` [E0425]
src\main.rs:3 let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
^~~~~~~~~~~~~~~~~~~
src\main.rs:3:18: 3:37 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:4:20: 4:39 error: failed to resolve. Could not find `Display` in `phone` [E0433]
src\main.rs:4 let display = phone::Display::new(10,20);
^~~~~~~~~~~~~~~~~~~
src\main.rs:4:20: 4:39 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:4:20: 4:39 error: unresolved name `phone::Display::new` [E0425]
src\main.rs:4 let display = phone::Display::new(10,20);
^~~~~~~~~~~~~~~~~~~
src\main.rs:4:20: 4:39 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:6:16: 6:31 error: failed to resolve. Could not find `GSM` in `phone` [E0433]
src\main.rs:6 let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
^~~~~~~~~~~~~~~
src\main.rs:6:16: 6:31 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:6:16: 6:31 error: unresolved name `phone::GSM::new` [E0425]
src\main.rs:6 let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
^~~~~~~~~~~~~~~
src\main.rs:6:16: 6:31 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:7:5: 7:16 error: the type of this value must be known in this context
src\main.rs:7 gsm.print();
I don't understand them, I searched here and in Google, but I failed to find a solution. Also I get a lot of warning that the methods in phone.rs are never used #[warn(dead_code)], any help is appreciated.

Short answer: you don't need the mod phone in phone.rs. Just remove that and your code will work (assuming the rest of the code is correct).
Longer answer: The following code in main.rs:
pub mod phone;
is equivalent to:
pub mod phone {
// literally insert the contents of phone.rs here
}
so you don't need to wrap everything in phone.rs in mod phone {}.
Your current code translates to:
pub mod phone {
pub mod phone {
pub struct Battery { ... }
...
}
}
which means you need to access Battery as phone::phone::Battery (and Display as phone::phone::Display, etc.) in main.rs.

Related

Why do I get "the method exists but the following trait bounds were not satisfied" when extending Result for failure types?

I'm trying to add a more concise version of the failure crate's .with_context(|e| format!("foo: {}", e)) to my code. Like this playground:
use failure::{Context, Fail, ResultExt}; // 0.1.5
/// Extension methods for failure `Result`.
pub trait ResultContext<T, E> {
/// Wraps the error type in a context type generated by looking at the
/// error value. This is very similar to `with_context` but much more
/// concise.
fn ctx(self, s: &str) -> Result<T, Context<String>>;
}
impl<T, E> ResultContext<T, E> for Result<T, E>
where
E: Fail,
{
fn ctx(self, s: &str) -> Result<T, Context<String>> {
self.map_err(|failure| {
let context = format!("{}: {}", s, failure);
failure.context(context)
})
}
}
pub fn foo() -> Result<i32, failure::Error> {
Ok(5i32)
}
pub fn main() -> Result<(), failure::Error> {
// This works.
let _ = foo().with_context(|_| "foo".to_string())?;
// This doesn't.
foo().ctx("foo")?
}
I get the following error:
error[E0599]: no method named `ctx` found for type `std::result::Result<i32, failure::error::Error>` in the current scope
--> src/main.rs:31:11
|
31 | foo().ctx("foo")?
| ^^^
|
= note: the method `ctx` exists but the following trait bounds were not satisfied:
`std::result::Result<i32, failure::error::Error> : ResultContext<_, _>`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `ctx`, perhaps you need to implement it:
candidate #1: `ResultContext`
I can't work out why. I more or less copied the existing with_context code.
As the compiler tells you, Result<i32, failure::error::Error> doesn't implement ResultContext<_, _>. You have added a bound to your implementation:
where
E: Fail,
But failure::Error doesn't implement failure::Fail:
use failure; // 0.1.5
fn is_fail<F: failure::Fail>() {}
pub fn main() {
is_fail::<failure::Error>();
}
error[E0277]: the trait bound `failure::error::Error: std::error::Error` is not satisfied
--> src/main.rs:6:5
|
6 | is_fail::<failure::Error>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `failure::error::Error`
|
= note: required because of the requirements on the impl of `failure::Fail` for `failure::error::Error`
note: required by `is_fail`
--> src/main.rs:3:1
|
3 | fn is_fail<F: failure::Fail>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You will need to alter your bounds or your type.

How do I use the Option::ok_or() method correctly?

I'm trying to understand how to use the question mark operator for error handling in Rust. I have this code:
fn main() -> Result<(), &'static str> {
let foo: i32 = Some("1")
.ok_or(Err("error 1"))?
.parse()
.or(Err("error 2"))?;
Ok(())
}
This code can not be compiled for some reason:
error[E0277]: the trait bound `&str: std::convert::From<std::result::Result<_, &str>>` is not satisfied
--> src/main.rs:2:20
|
2 | let foo: i32 = Some("1")
| ____________________^
3 | | .ok_or(Err("error 1"))?
| |_______________________________^ the trait `std::convert::From<std::result::Result<_, &str>>` is not implemented for `&str`
|
= note: required by `std::convert::From::from`
The Rust book has an example usage of the question mark operator:
use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
In my opinion, it doesn't differ much from my example in sense of handling errors. I cannot see a reason for my code to be invalid. If the From trait should be implemented for all kinds of Result why does the code from the Rust book work fine?
Unlike or, ok_or takes an E, not a full Result<T, E> (because it wouldn't have anything to do if passed an Ok). Just pass the error string directly:
fn main() -> Result<(), &'static str> {
let foo: i32 = Some("1")
.ok_or("error 1")?
.parse()
.or(Err("error 2"))?;
Ok(())
}
The reason the error message mentions the From trait is because ? implicitly uses From to convert the expression's error type into the return value's error type. If it worked, .ok_or(Err("error 1")) would return a value of Result<&'static str, Result<_, &'static str>> (_ could be almost anything, since Err doesn't specify). The ? operator attempts to find an implementation of From that would convert Result<_, &'static str> (the expression's error type) into &'static str (the return value's error type). Since no such From implementation exists, the compiler emits an error.

How do I divide my Rust code between two source files? [duplicate]

I created a simple project for educational purpose, so I have a main function and 3 traits Battery, Display and GSM and implementations for them. I want the the main function to be in file main.rs and the 3 traits in another file called phone.rs:
phone.rs
mod phone{
pub struct Battery{
model : String,
hours_idle : i16,
hours_talk : i16
}
pub struct Display{
size : i16,
number_of_colors : i32
}
pub struct GSM{
model : String,
manufactor : String,
price : f32,
owner : String,
battery: Battery,
display : Display
}
impl Battery {
pub fn new(model : String, hours_idle : i16, hours_talk : i16) -> Battery{
Battery {model : model, hours_idle : hours_idle ,hours_talk : hours_talk}
}
pub fn print(&self){
println!("Battery model: {}", self.model);
println!("Hours idle: {}", self.hours_idle);
println!("hours talk: {}", self.hours_talk);
}
}
impl Display {
pub fn new(size: i16, number_of_colors : i32) -> Display{
Display{size : size, number_of_colors : number_of_colors}
}
pub fn print(&self){
println!("size: {}", self.size);
println!("number_of_colors: {}", self.number_of_colors);
}
}
impl GSM {
pub fn new(model : String, manufactor : String, price : f32, owner : String, battery : Battery, display : Display) -> GSM{
GSM{model : model, manufactor : manufactor, price : price, owner : owner, battery : battery, display : display }
}
pub fn print(&self){
println!("Model: {}, Manufactor: {}", self.model, self.manufactor);
println!("price: {}", self.price);
println!("owner: {}", self.owner);
self.battery.print();
self.display.print();
}
}
}
main.rs
pub mod phone;
fn main(){
let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
let display = phone::Display::new(10,20);
//model : String, manufactor : String, price : f32, owner : String, baterry : Battery, display : Display
let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
gsm.print();
}
At first, everything was in one file (main.rs) and everything worked fine (there was some difference for example I added phone:: in front of Display, GSM and Battery in main.rs), when I moved the traits and added mod phone{} in phone.rs, and pub mod phone in main.rs, I got the following errors from the compiler:
src\main.rs:3:18: 3:37 error: failed to resolve. Could not find `Battery` in `phone` [E0433]
src\main.rs:3 let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
^~~~~~~~~~~~~~~~~~~
src\main.rs:3:18: 3:37 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:3:18: 3:37 error: unresolved name `phone::Battery::new` [E0425]
src\main.rs:3 let battey = phone::Battery::new("modelBattery".to_string(), 1,2);
^~~~~~~~~~~~~~~~~~~
src\main.rs:3:18: 3:37 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:4:20: 4:39 error: failed to resolve. Could not find `Display` in `phone` [E0433]
src\main.rs:4 let display = phone::Display::new(10,20);
^~~~~~~~~~~~~~~~~~~
src\main.rs:4:20: 4:39 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:4:20: 4:39 error: unresolved name `phone::Display::new` [E0425]
src\main.rs:4 let display = phone::Display::new(10,20);
^~~~~~~~~~~~~~~~~~~
src\main.rs:4:20: 4:39 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:6:16: 6:31 error: failed to resolve. Could not find `GSM` in `phone` [E0433]
src\main.rs:6 let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
^~~~~~~~~~~~~~~
src\main.rs:6:16: 6:31 help: run `rustc --explain E0433` to see a detailed explanation
src\main.rs:6:16: 6:31 error: unresolved name `phone::GSM::new` [E0425]
src\main.rs:6 let gsm = phone::GSM::new("modelPhone".to_string(), "manufactor".to_string(), 100.0, "owner".to_string(), battey, display);
^~~~~~~~~~~~~~~
src\main.rs:6:16: 6:31 help: run `rustc --explain E0425` to see a detailed explanation
src\main.rs:7:5: 7:16 error: the type of this value must be known in this context
src\main.rs:7 gsm.print();
I don't understand them, I searched here and in Google, but I failed to find a solution. Also I get a lot of warning that the methods in phone.rs are never used #[warn(dead_code)], any help is appreciated.
Short answer: you don't need the mod phone in phone.rs. Just remove that and your code will work (assuming the rest of the code is correct).
Longer answer: The following code in main.rs:
pub mod phone;
is equivalent to:
pub mod phone {
// literally insert the contents of phone.rs here
}
so you don't need to wrap everything in phone.rs in mod phone {}.
Your current code translates to:
pub mod phone {
pub mod phone {
pub struct Battery { ... }
...
}
}
which means you need to access Battery as phone::phone::Battery (and Display as phone::phone::Display, etc.) in main.rs.

Figuring out return type of closure

I'm having troubles figuring out the type signature of the fn filter function in following example.
The Node and Descendant definition is just there for syntax . It's not meant to do anything!
use std::iter::Filter;
#[derive(Clone)]
pub struct Node<'a> {
s: &'a str,
}
pub struct Descendants<'a>{
iter: Node<'a>
}
impl<'a> Iterator for Descendants<'a> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Node<'a>> {
Some(Node {s: self.iter.s})
}
}
impl<'a> Node<'a> {
pub fn descendants(&self) -> Descendants<'a> {
Descendants{ iter: Node{s: self.s} }
}
pub fn filter(&self, criteria: &str) -> Filter<Descendants<'a>, fn(&'a Node<'a>)->bool > {
self.descendants()
.filter(|node| node.s == "meh")
}
}
fn main() {
let doc = Node{s: "str"};
}
(Playground link)
The error I get is following:
<anon>:27:28: 27:34 error: the type of this value must be known in this context
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~
<anon>:27:21: 27:43 error: mismatched types:
expected `fn(&Node<'_>) -> bool`,
found `[closure <anon>:27:21: 27:43]`
(expected fn pointer,
found closure) [E0308]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~
<anon>:27:14: 27:44 error: type mismatch: the type `fn(&Node<'_>) -> bool` implements the trait `core::ops::FnMut<(&Node<'_>,)>`, but the trait `for<'r> core::ops::FnMut<(&'r Node<'_>,)>` is required (expected concrete lifetime, found bound lifetime parameter ) [E0281]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:27:14: 27:44 error: type mismatch resolving `for<'r> <fn(&Node<'_>) -> bool as core::ops::FnOnce<(&'r Node<'_>,)>>::Output == bool`:
expected bound lifetime parameter ,
found concrete lifetime [E0271]
<anon>:27 .filter(|node| node.s == "meh")
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 4 previous errors
playpen: application terminated with error code 101
When I as per this question Correct way to return an Iterator? I tried to replace pub fn filter(&self, criteria: &str) -> Filter<Descendants<'a>, fn(&'a Node<'a>)->bool > with pub fn filter(&self, criteria: &str) -> () I get
<anon>:26:9: 27:44 error: mismatched types:
expected `()`,
found `core::iter::Filter<Descendants<'_>, [closure <anon>:27:21: 27:43]>`
What I'm supposed to replace closure with?
Alternatively, if it's too hard and finicky to return a Filter, how do I write the Wrapper for fn filter() return type?
I clearly remember that this was answered before a few times (I even wrote about it in an answer a few minutes before) but I can't find a link now, so here it goes.
The problem with your code is that you use a closure as filter() argument:
.filter(|node| node.s == "meh")
Unboxed closures in Rust are implemented as anonymous types which, naturally, can't be named, so there is no way to write a signature of a function which returns an iterator which uses a closure. That's what the error message you're getting is about:
expected `fn(&Node<'_>) -> bool`,
found `[closure <anon>:27:21: 27:43]`
(expected fn pointer,
found closure) [E0308]
There are several ways around this, one of them is to use trait objects:
pub fn filter<'b>(&'b self, criteria: &'b str) -> Box<Iterator<Item=Node<'a>+'b>>
{
Box::new(self.descendants().filter(move |node| node.s == criteria))
}
Given that your closure has a non-empty environment, this is the only way for your code to work. If your closure didn't capture anything, you could use a static function whose type can be written out:
pub fn filter(&self) -> Filter<Descendants<'a>, fn(&Node<'a>) -> bool> {
fn filter_fn<'b>(node: &Node<'b>) -> bool {
node.s == "meh"
}
self.descendants().filter(filter_fn)
}

Matching on the result of File::create

I am trying to write a library which must open files and I want to handle the Result type used by std::fs::File::create. I cannot figure out how to match on the return result given this wrapper function:
use std::fs::File;
use std::path::Path;
use std::fs::File;
use std::path::Path;
pub fn allocate(path:& str) -> File{
let mut file = File::create(Path::new(path));
}
which is then invoked:
mod whisper;
use std::io::Write;
fn main(){
let mut handle = whisper::allocate("./a_file.wsp");
match handle {
Ok(_) => println!("success!"),
Err(e) => println!("sorry, got {}",e),
}
return;
}
but the code doesn't compile due to a type mismatch:
Xaviers-MacBook-Pro:graphite-rust xavierlange$ cargo build
Compiling graphite-rust v0.0.1 (file:///Users/xavierlange/code/viasat/graphite-rust)
src/main.rs:8:5: 8:10 error: mismatched types:
expected `std::fs::File`,
found `core::result::Result<_, _>`
(expected struct `std::fs::File`,
found enum `core::result::Result`) [E0308]
src/main.rs:8 Ok(_) => println!("hi!"),
^~~~~
src/main.rs:9:5: 9:11 error: mismatched types:
expected `std::fs::File`,
found `core::result::Result<_, _>`
(expected struct `std::fs::File`,
found enum `core::result::Result`) [E0308]
src/main.rs:9 Err(e) => println!("sorry, got {}",e),
^~~~~~
error: aborting due to 2 previous errors
Could not compile `graphite-rust`.
The signature for std::fs::File::create is fn create<P: AsRef<Path>>(path: P) -> Result<File> so shouldn't I be expecting to "unwrap" the value using match? Why is it expecting a File value?
Let's look at a simplified version of your code, an MCVE. It's very useful to create small examples when programming, as it helps you concentrate on a single problem at a time:
use std::fs::File;
use std::path::Path;
fn allocate(path: &str) -> File {
File::create(Path::new(path))
}
fn main() {}
(I also took the liberty of aligning your code with the prevailing Rust style; I highly encourage you to learn it and love it for better community interaction!)
This gives the same error when run on the Playpen:
<anon>:5:5: 5:34 error: mismatched types:
expected `std::fs::File`,
found `core::result::Result<std::fs::File, std::io::error::Error>`
(expected struct `std::fs::File`,
found enum `core::result::Result`) [E0308]
<anon>:5 File::create(Path::new(path))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The problem is because you have defined the return type of your function as a File, but the body of your function is returning a Result!
fn allocate(path: &str) -> File
You need to ensure that the type on your function and what the function does align. The simplest is to unwrap the result, which causes a thread panic on failure cases.
fn allocate(path: &str) -> File {
File::create(Path::new(path)).unwrap()
}
You could also return a Result of your own, and then force the caller to deal with failure (my preferred choice):
use std::io;
fn allocate(path: &str) -> io::Result<File> {
File::create(Path::new(path))
}
The other way of looking at your error is this half:
use std::fs::File;
fn allocate() -> File { unimplemented!() }
fn main() {
match allocate() {
Ok(..) => println!("OK!"),
Err(..) => println!("Bad!"),
}
}
Here, we are trying to match on a File, but File is not an enumeration with the variants Ok and Err - that would be Result! Thus, you get an error indicating such:
<anon>:7:9: 7:15 error: mismatched types:
expected `std::fs::File`,
found `core::result::Result<_, _>`
(expected struct `std::fs::File`,
found enum `core::result::Result`) [E0308]
<anon>:7 Ok(..) => println!("OK!"),
^~~~~~