What are the use cases of raw identifiers besides

2019-07-04 01:29发布

As in Rust 2018, we now have raw identifiers:

This feature is useful for a few reasons, but the primary motivation was inter-edition situations. For example, try is not a keyword in the 2015 edition, but is in the 2018 edition. So if you have a library that is written in Rust 2015 and has a try function, to call it in Rust 2018, you'll need to use the raw identifier.

Are there any other advantages than stated above? Are there plans to make keywords contextual, e.g. you can use type as identifier for variables? Why I should use a cryptic syntax like r#type instead of ty or something else?

2条回答
姐就是有狂的资本
2楼-- · 2019-07-04 01:57

Ineed with raw_identifiers you can use type and other keywords as a variable/struct/etc. identifiers:

#![feature(rust_2018_preview)]
#![feature(raw_identifiers)]

struct r#let {} // just warnings: struct is never used: `let` and type `let` should have a camel case name such as `Let`

fn main() {
    let r#type = 0; // just warning: unused variable: `type`
}

It doesn't work with every keyword, though:

let r#super = 0; // error: `r#super` is not currently supported.
查看更多
别忘想泡老子
3楼-- · 2019-07-04 02:08

Why I should use a cryptic syntax like r#type instead of ty or something else?

Sometimes the names of fields are used outside of your Rust program. For example, when serializing data with Serde, the field name is used in the output (e.g. JSON). So if you need JSON output with this:

"type": 27,

... then raw identifiers can help you:

#[derive(Serialize)]
struct Foo {
    r#type: u32,
}

On the other hand... Serde already has a way to achieve what you want: the #[serde(rename = "name")] attribute. Reserved Rust keywords are one of the reasons why this attribute was introduced.

#[derive(Serialize)]
struct Foo {
    #[serde(rename = "type")]
    ty: u32,
}

Similarly, the Debug output also uses the field name in its output. So if you want the output Foo { type: 27 }, you can use raw identifiers:

#[derive(Debug)]
struct Foo {
    r#type: u32,
}

On the other hand... if the exact Debug output is that important to you, you can simply implement it yourself:

impl fmt::Debug for Foo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Foo")
            .field("type", &self.ty)
            .finish()
    }
}

So in practice, I don't see why one would use raw identifier for this purpose, since you have to use the strange r# syntax everywhere you use that name. It's probably easier to just fix this particular problem in another way.

So, as far as I see it, the "using API from another edition" is the only real use case for raw identifiers. Having such a syntax "just for the case" is a nice thing, though.

查看更多
登录 后发表回答