I am sorry if this turns out to be a duplicate, or an issue directly related with some other issue. I am relatively new to the language.
The following (also linked here) will compile just fine with cargo run or cargo build. However, when compiled with rustc, I get a compile error:
Code:
// A Person struct with name, age and health status
#[derive(Debug)]
struct Person {
/// Name of the person
name: String,
/// Age of the person
age: u32,
/// The health status of the person
status: Status,
}
// Create a constructor for the Person struct
impl Person {
fn new(n: String, a: u32, s: Status) -> Self {
Person {
name: n,
age: a,
status: s,
}
}
}
// A Disease struct with symptoms, curability and medication information
#[derive(Debug)]
struct Disease {
/// Whether or not the disease is curable
curable: bool,
/// A list of symptoms
symptoms: Vec<String>,
/// The recommended medication
medication: String,
}
// Make a constructor for the Disease struct
impl Disease {
fn new(curable: bool, symptoms: Vec<String>, medication: String) -> Self {
Disease {
curable,
symptoms,
medication,
}
}
}
// Enum with 2 variants: Healthy and Sick
#[derive(Debug)]
enum Status {
/// Variant indicating that the person is healthy
Healthy,
/// Variant indicating that the person is sick
Sick(Vec<Disease>),
}
// Trait for the current status of a person's health
trait Sick {
/// Return the diseases someone has, if any.
/// A None is returned if someone is not sick
fn sickness(&self) -> Option<&Vec<Disease>>;
/// Check whether or not someone is sick
fn is_sick(&self) -> bool;
/// Make someone sick by adding the provided
/// disease to their list of diseases
fn sicken(&mut self, d: Disease);
}
// Implement the Sick trait for Person
impl Sick for Person {
fn sickness(&self) -> Option<&Vec<Disease>> {
match &self.status {
Status::Healthy => None,
Status::Sick(d) => Some(d),
}
}
fn is_sick(&self) -> bool {
self.sickness().is_some()
}
fn sicken(&mut self, d: Disease) {
match &mut self.status {
Status::Healthy => {
self.status = Status::Sick(vec![d])
},
Status::Sick(diseases) => {
diseases.push(d);
}
}
}
}
// Bring everything together
fn main() {
// Let there be healthy Mireille
let mut p = Person::new(String::from("Mireille"), 45, Status::Healthy);
println!("{:#?}", p.sickness());
println!("{}", p.is_sick());
// Make up some disease
let d = Disease::new(
true,
vec![String::from("Sore throat")],
String::from("Sleep"),
);
// Infect Mireille with it
p.sicken(d);
// Make another one
let d = Disease::new(
true,
vec![String::from("Headache")],
String::from("Aspirin"),
);
// Sicken her even more
p.sicken(d);
// Check for diseases
println!("{:#?}", p.sickness().unwrap());
}
Error with rustc:
error[E0506]: cannot assign to `self.status` because it is borrowed
--> sicklies.rs:80:17
|
78 | match &mut self.status {
| ----------- borrow of `self.status` occurs here
79 | Status::Healthy => {
80 | self.status = Status::Sick(vec![d])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.status` occurs here
I have, quite frankly, come to terms with the fact that the borrow checker is right about the error here. self.status is mutably borrowed at match &mut self.status; so reassigning it with the line self.status = Status::Sick(vec![d]) should trigger an error. Hence, I see that error by directly invoking rustc. Not seeing the same error with cargo has me confused.
Summary:
rustc 1.34.2 (6c2484dc3 2019-05-13)
binary: rustc
commit-hash: 6c2484dc3c532c052f159264e970278d8b77cdc9
commit-date: 2019-05-13
host: x86_64-apple-darwin
release: 1.34.2
LLVM version: 8.0
or
rustc 1.34.1 (fc50f328b 2019-04-24)
binary: rustc
commit-hash: fc50f328b0353b285421b8ff5d4100966387a997
commit-date: 2019-04-24
host: x86_64-unknown-linux-gnu
release: 1.34.1
LLVM version: 8.0
or
rustc 1.33.0 (2aa4c46cf 2019-02-28)
binary: rustc
commit-hash: 2aa4c46cfdd726e97360c2734835aa3515e8c858
commit-date: 2019-02-28
host: x86_64-unknown-linux-gnu
release: 1.33.0
LLVM version: 8.0
cargo 1.33.0 (f099fe94b 2019-02-12)
release: 1.33.0
commit-hash: f099fe94b66f0a2f80370be8f2d3db2a55b97050
commit-date: 2019-02-12
and
cargo 1.34.0 (6789d8a0a 2019-04-01)
release: 1.34.0
commit-hash: 6789d8a0a54a96d95365c4e1fb01d47a5eed9937
commit-date: 2019-04-01
Questions:
Is this a bug or am I missing something?
Thank you,
Abdou
The default edition in rustc is 2015. New cargo projects default to 2018. 2018 now uses non-lexical lifetimes. rustc 1.36 (beta) will also use NLL in the 2015 edition, but the versions you have do not.
If you want to use the rustc command line, pass --edition=2018.
@ehuss Thank you! That's definitely something I missed. I will use the information to see how it applies to my code.
@AbdouSeck filed #61914 for a more holistic approach to these kind of edition discrepancies. This particular problem will go away once we enable NLL in 2015 edition, but the general problem of discrepancies between editions not being explained when encountered are a paper cut that needs fixing.
@estebank Thanks for making that clear. Please don't hesitate to ask if I can be of any help; especially with documentation. It may take me a little bit to navigate and fully understand the structure of the project though. So, any guidance will be appreciated.
Most helpful comment
The default edition in rustc is 2015. New cargo projects default to 2018. 2018 now uses non-lexical lifetimes. rustc 1.36 (beta) will also use NLL in the 2015 edition, but the versions you have do not.
If you want to use the rustc command line, pass
--edition=2018.