2
votes

I have a main.rs file and a logging module inside logging.rs file. My file layout is:

.
├── Cargo.toml
├── src
│   ├── logging.rs
│   └── main.rs

The contents of my main.rs

mod logging;
fn main(){}

The contents of logging.rs

extern crate serialize;

use self::serialize::{json, Encoder, Encodable};

#[deriving(Encodable)]
pub struct Person {
  pub age: i32
}

However this does not compile. The error is:

error: failed to resolve. Did you mean `self::serialize`?
/Users/valentin/../src/logging.rs:7 #[deriving(Encodable)]

Three questions:

  1. Why does not it compile?
  2. Why does moving the struct and use directive to main.rs makes it compile?
  3. Why does changing serialize::Encodable to Show trait makes it compile even inside logging module?

However If I add

extern crate serialize;

use self::serialize::{json, Encoder, Encodable};

to main.rs, it all starts compiling.

This is very confusing, the fourth questions is why isn't it sufficient to have only one extern crate + use serialize::.. inside logging module?

1

1 Answers

3
votes

Let’s look at the code that’s generated, with rustc main.rs --pretty expanded:

#![feature(phase)]
#![no_std]
#![feature(globs)]
#[phase(plugin, link)]
extern crate std = "std";
extern crate rt = "native";
use std::prelude::*;
mod logging {
    extern crate serialize;
    use std::prelude::*;

    use self::serialize::{json, Encoder, Encodable};

    pub struct Person {
        pub age: i32,
    }
    #[automatically_derived]
    impl <__S: ::serialize::Encoder<__E>, __E>
         ::serialize::Encodable<__S, __E> for Person {
        fn encode(&self, __arg_0: &mut __S) ->
         ::std::result::Result<(), __E> {
            match *self {
                Person { age: ref __self_0_0 } =>
                __arg_0.emit_struct("Person", 1u, |_e| {
                                    return _e.emit_struct_field("age", 0u,
                                                                |_e|
                                                                    (*__self_0_0).encode(_e));
                                }),
            }
        }
    }
}

fn main() { }

This demonstrates that the #[deriving(Encodable)]expands to stuff involving the paths ::serialize::*; that is, the item serialize from the crate root.

Now, extern crate serialize; from inside mod logging means that the path to serialize is ::logging::serialize, which is also accessible as self::serialize inside the module; there is no ::serialize.

The solution is moving the extern crate serialize; into the crate root. (This is where all extern crate definitions should be.) This is what fixed it for you, not the use self::serialize::{json, Encoder, Encodable};.