In this post I would like to discuss names in Rust: constants, statics, independent functions, types, associated functions, methods, enum variants, and field names (Have I left out anything?). I now give a simple program to illustrate the above.
mod moda {
pub const ZERO:i32 = 0;
pub static UNITY:i32 = 1;
pub fn increment(r: &mut i32) {
*r += 1;
}
}
mod modb {
pub struct Point {pub x:i32, pub y:i32}
impl Point {
pub fn new()->Point {
Point{x:0, y:0}
}
pub fn mirror(&mut self) {
self.x = -self.x;
self.y = -self.y;
}
}
pub enum Dir {Left, Down, Right, Up}
}
fn main() {
let z = moda::ZERO;
let mut u = moda::UNITY;
moda::increment(&mut u);
let mut p = modb::Point {x:2, y:-3};
let q = modb::Point::new();
p.mirror();
println!("{z} {u} ({},{}) ({},{})", p.x, p.y, q.x, q.y);
println!("{} {} {} {}", modb::Dir::Left as i32, modb::Dir::Down as i32,
modb::Dir::Right as i32, modb::Dir::Up as i32);
}
Any name begins with a module path (can be empty if in the same module), then followed by other types of names. I also found the following rules (correct me if there are any errors):
- Constants, statics, independent functions must immediately follow a module name and then end (i.e. cannot be followed by anything like ::name)
- Types (including structs, enums and other type names) must immediately follow a module name but can have a further level of branch names (i.e. followed by something like ::name ).
- Associated functions, methods must follow a struct or enum type name and then end.
- Enum variants must immediately follow a enum name and then end.
- Field names need not begin with a path, because they always follow a variable or constant name, which already has the path imformation.
Look at the above rules (especially 1 and 3), it may seem like we are not allowed to define types or functions within a function. But actually it isn't so. We can! It is only that we can only refer to names that are defined in functions in the SAME or an ancestor scope. Let us see an example:
// This snippet does not compile!
fn myfun() {
pub const ZERO:i32 = 0;
pub fn increment(r: &mut i32) {
*r += 1;
}
}
fn main() {
let mut z = myfun::ZERO;
increment(&mut z);
}
Rustc gives the following error info:
Now let revise the code to use the names in the same scope or an ancestor scope (parent scope in the code).
fn main() {
fn sub() {
let z = ZERO;
let mut u = UNITY;
increment(&mut u);
let mut p = Point { x: 2, y: -3 };
let q = Point::new();
p.mirror();
println!("{z} {u} ({},{}) ({},{})", p.x, p.y, q.x, q.y);
println!(
"{} {} {} {}",
Dir::Left as i32,
Dir::Down as i32,
Dir::Right as i32,
Dir::Up as i32
);
}
sub();
const ZERO: i32 = 0;
static UNITY: i32 = 1;
fn increment(r: &mut i32) {
*r += 1;
}
struct Point {
x: i32,
y: i32,
}
impl Point {
fn new() -> Point {
Point { x: 0, y: 0 }
}
fn mirror(&mut self) {
self.x = -self.x;
self.y = -self.y;
}
}
enum Dir {Left, Down, Right, Up}
}
The program compiles just fine and produces the desired result!
PS: It seems to me that the above findings have not yet been properly documented in any book or web material. If I am wrong, could you please give me any pointer? Also, please correct me if there is any inaccuracy and help me improve this post. Thank you very much!