0

I'm fairly new to Rust so I came across this piece of code in the official Guide

let input = io::stdin().read_line()
                       .ok()
                       .expect("Failed to read line");
let input_num: Option<uint> = from_str(input.as_slice());

let num = match input_num {
    Some(num) => num,
    None      => {
        println!("Please input a number!");
        return;
    }
};

While the understand the first two statements (on input and inputnum), I'm not quite sure about the match statement. So I checked the documentation which shows that Option<T> can take two values , either None or Some(T) for some (object?) T. So I tested the following code:

io::println( 
    match input_num {
        Some(num) => "somenum",
        None      => {
            println!("Please input a number only!");
            return;
        }
    }
);

This code works as expected; it prints somenum if you enter a number and otherwise it prints the error message. However, the compiler gives a warning stating: warning: unused variable:num, #[warn(unused_variable)] on by default. This confirmed my suspicions that the num inside the `match is used as a variable.

Question: How is it possible that rust does not complain about (in the Guide's example) having two variables with the same name num? Or does it "hand over" the pointer to the inside num to the outside num? Also in the case of an empty return what exactly is returned? I'm guessing it is unit () because it is mentioned here that

functions without a -> ... implicitly have return type ()

Edit: Sorry for missing the obvious point. The return directly exits the function without bothering to put anything into num.

P.S. I noticed that using cargo build to compile does not give warnings the second time around (not making any changes). Does cargo keep tracking of versions or something?

typesanitizer
  • 2,505
  • 1
  • 20
  • 44

1 Answers1

1

Do you have any experiences with Java or C#? Many mainstream programing languages allows you to shadow a variable with another variable with the same name in a new block scope. For example, take a look at this C# code:

using System;

public class Test
{
    public static void Main()
    {
        int x = 10;
        {
            int x = 20;
            Console.WriteLine(x);
        }
        Console.WriteLine(x);
    }
}

In fact Rust is more flexible in terms of shadowing: you can shadow variables as many times as you want without explicitly making a brace block.

fn main() {
    let i = 10i32;
    let i = "foo";
    println!("{}", i);
}

Here, the first i and the second i have no relationships. We just lose a way to use (refer to) the first i.

This confirmed my suspicions that the num inside the `match is used as a variable.

Yes, pattern matching can introduce new variables. But the new variable num introduced by pattern matching has no direct relationship with the outer num whose value is being given by the match expression.

I can translate your Rust code into less idiomatic Rust to illustrate what was happening:

let num =
    if input_num.is_some() {
        let num = input_num.unwrap();
        num
    } else {
        println!("Please input a number!");
        return;
    }
;

As for not observing warnings from cargo build, I suspect it was because Cargo had already built .o from your code and didn't bother to repeat the same job twice, knowing that there was no change in your code.

nodakai
  • 7,773
  • 3
  • 30
  • 60
  • In 9 months of Java programming, I hadn't encountered a single example of shadowing. Perhaps because it is a bit confusing. Thanks for the links and extra information. – typesanitizer Sep 25 '14 at 16:49
  • Hmm, I found Java is indeed much less permissive with shadowing http://doanduyhai.wordpress.com/2012/07/07/variable-shadowing/ http://stackoverflow.com/questions/4623334/question-about-variable-scope-and-shadowing-in-java http://stackoverflow.com/questions/141140/why-does-java-not-have-block-scoped-variable-declarations No wonder you haven't had any chances to encounter it. – nodakai Sep 25 '14 at 16:59
  • 1
    In Rust you have pattern matching and everything-is-an-expression doctrine. These nudge you towards instances of name shadowing. Java doesn’t have either, so it’s no surprise that you don’t get as much shadowing happening. – Chris Morgan Sep 25 '14 at 22:59