Skip to content

Commit

Permalink
update decl: identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
zjp-CN committed Apr 18, 2022
1 parent dfb2314 commit f3ae4c9
Showing 1 changed file with 53 additions and 54 deletions.
107 changes: 53 additions & 54 deletions src/decl-macros/minutiae/identifiers.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# 非标识符的“标识符”

> 译者注:这一章的内容“**可能**”有些过时。(需要大佬帮助说明!)
> 译者注:这里需要记住的重点是
>
> 根据我的理解,主要是讲 Rust 语法里的关键字在 `macro_rules!` 中可使用 [`ident`] 或者 [`tt`]
分类符来匹配。当然,不仅仅是这里例举的 `self`,可以是任何关键字。
> 1. `self` 可以使用 [`ident`] 或者 [`tt`] 分类符来匹配;
>
> 对于 `_` ,它只能在模式中使用,声明宏中不能用 [`ident`] 分类符匹配,
> 而是用 [`pat`] 或者 [`tt`] 分类符。
>
> 你可以在 [片段分类符] 一章的 13 种分类符的所有样板代码块中编辑运行代码,
> 尝试验证你认为的 token 属于哪种。
>
> 以下为原文。
> 2. `_` 只能在模式中使用,不能用 [`ident`] 分类符匹配,而是用 [`pat`] 或者
> [`tt`] 分类符匹配。
有两个标记,当你最终撞见时,很有可能认为它们是标识符 ([`ident`]),但实际上它们不是。

有两个标记,当你撞见时,很有可能最终认为它们是标识符 ([`ident`]),但实际上它们不是。
然而正是这些标记,在某些情况下又的确是标识符。

第一个是 `self`
毫无疑问,它是一个 **关键词** (keyword)。
在一般的 Rust 代码中,不可能出现把它解读成标识符的情况;
但在宏中这种情况则有可能发生:
## `self`

第一个是 `self`。毫无疑问,它是一个 **关键词** ([keyword])。在一般的 Rust
代码中,不可能出现把它解读成标识符的情况;但在宏中这种情况则有可能发生:

[keyword]: https://doc.rust-lang.org/reference/keywords.html

```rust,editable
macro_rules! what_is {
Expand All @@ -44,10 +41,8 @@ the keyword `self`
the keyword `self`
```

但这没有任何道理!
`call_with_ident!` 要求一个标识符,而且它的确匹配到了,还成功替换了!
所以,`self` 同时是一个关键词,但又不是。
你可能会想,好吧,但这鬼东西哪里重要呢?看看这个:
但这说不通啊!`call_with_ident!` 要求一个标识符,而且它的确匹配到了,还成功替换了!所以,
`self` 同时是一个关键词,但又不是。你可能会想,好吧,但这鬼东西哪里重要呢?看看这个:

```rust,editable
macro_rules! make_mutable {
Expand All @@ -63,15 +58,15 @@ impl Dummy {
self
}
}
#
# fn main() {
# println!("{:?}", Dummy(4).double().0);
# }
fn main() {
println!("{:?}", Dummy(4).double().0);
}
```

编译它会失败,并报错:

```text
```rust,ignore
error: `mut` must be followed by a named binding
--> src/main.rs:2:24
|
Expand All @@ -84,10 +79,9 @@ error: `mut` must be followed by a named binding
= note: `mut` may be followed by `variable` and `variable @ pattern`
```

所以说,宏在匹配的时候,会欣然把self当作标识符接受,
进而允许你把 `self` 带到那些实际上没办法使用的情况中去。
但是,也成吧,既然得同时记住 `self` 既是关键词又是标识符,
那下面这个讲道理应该可行,对吧?
所以说,宏在匹配的时候,会欣然把 `self` 当作标识符接受,进而允许你把 `self`
带到那些实际上没办法使用的情况中去。但是,也成吧,既然得同时记住 `self`
既是关键词又是标识符,那下面这个讲道理应该可行,对吧?

```rust,editable
macro_rules! make_self_mutable {
Expand All @@ -103,15 +97,15 @@ impl Dummy {
mut_self
}
}
#
# fn main() {
# println!("{:?}", Dummy(4).double().0);
# }
fn main() {
println!("{:?}", Dummy(4).double().0);
}
```

实际上也不行,编译错误变成:

```text
```rust,ignore
error[E0424]: expected value, found module `self`
--> src/main.rs:2:33
|
Expand All @@ -128,9 +122,8 @@ error[E0424]: expected value, found module `self`
|
```

这同样也没有任何道理。
这简直就像是在抱怨说,它看见的两个 `self` 不是同一个 `self` ...
就搞得像关键词 `self` 就像标识符一样,也有卫生性。
这同样也说不通。这简直就像是在抱怨说,它看见的两个 `self` 不是同一个 `self`
... 就搞得像关键词 `self` 就像标识符一样,也有卫生性。

```rust,editable
macro_rules! double_method {
Expand All @@ -149,10 +142,10 @@ impl Dummy {
self
}}
}
#
# fn main() {
# println!("{:?}", Dummy(4).double().0);
# }
fn main() {
println!("{:?}", Dummy(4).double().0);
}
```

还是报同样的错。那这个如何:
Expand All @@ -174,16 +167,18 @@ impl Dummy {
self
}}
}
#
# fn main() {
# println!("{:?}", Dummy(4).double().0);
# }
fn main() {
println!("{:?}", Dummy(4).double().0);
}
```

终于管用了。
所以说,`self` 是关键词,但如果想它变成标识符,那么同时也能是一个标识符。
终于管用了。所以说,`self` 是关键词,但如果想它变成标识符,那么同时也能是一个标识符。

那么,相同的道理对类似的其它东西有用吗?

## `_`

```rust,editable
macro_rules! double_method {
($self_:ident, $body:expr) => {
Expand All @@ -198,13 +193,13 @@ struct Dummy(i32);
impl Dummy {
double_method! {_, 0}
}
#
# fn main() {
# println!("{:?}", Dummy(4).double().0);
# }
fn main() {
println!("{:?}", Dummy(4).double().0);
}
```

```text
```rust,ignore
error: no rules expected the token `_`
--> src/main.rs:12:21
|
Expand All @@ -215,11 +210,15 @@ error: no rules expected the token `_`
| ^ no rules expected this token in macro call
```

哈,当然不行。
`_` 在模式以及表达式中是一个有效关键词,而不是一个标识符;
即便它 *如同* `self` 一样从定义上讲符合标识符的特性。
哈,当然不行。即便它 **如同** `self` 一样从定义上讲是标识符,但 [`_`][_]
在模式以及表达式中是一个合法的 (valid) 关键词,而不是一个标识符。

[_]: https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern

---

你可能觉得,既然 `_` 在模式中有效,那换成 `$self_:pat` 是不是就能一石二鸟了呢?

可惜了,也不行,因为 `self` 不是一个有效的模式。

如果你真想同时匹配这两个标记,仅有的办法是换用 `tt` 来匹配。
Expand Down

0 comments on commit f3ae4c9

Please sign in to comment.