陷阱
今天又看了一遍”The Rust Programming Language”,没想到竟然跳进了一个坑里面。。
先说一个新的东西Loop labels
'outer: for x in 0..10 {
'inner: for y in 0..10 {
if x % 2 == 0 { continue 'outer; } // continues the loop over x
if y % 2 == 0 { continue 'inner; } // continues the loop over y
println!("x: {}, y: {}", x, y);
}
}
感觉像是不是goto
又像是goto
的东西,更像是Ruby里的修饰,这个循环标签适合于循环中的continue
和break
,总之这个东西能够在嵌套循环中减少些代码。
那么问题来了,怎样实现 let x = "a" + "b"
呢? 懂一点C++的人不加思考的话会说运算符重载,当让他们写这个重载的时候,他们就无从下手了。
我今天就是跳进了这个坑里面。。。
use std::ops::Add;
impl<'a> Add<&'a str> for &'a str {
fn add(self, other: &'a str) -> &str {
let res = self.to_string() + other;
res.as_str()
}
}
fn main() {
let (x, y) = ("this", "is");
let z = x + y;
assert_eq!("thisis", z);
}
多么简单的代码。但是,虽然不像C++那样无从下手,这个代码是通不过编译的!
t.rs:3:1: 8:2 error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
t.rs:3 impl<'a> Add<&'a str> for &'a str {
t.rs:4 fn add(self, other: &'a str) -> &str {
t.rs:5 let res = self.to_string() + other;
t.rs:6 res.as_str()
t.rs:7 }
t.rs:8 }
t.rs:3:1: 8:2 help: run `rustc --explain E0117` to see a detailed explanation
error: aborting due to previous error
这个错误的解释(rustc --explain E0117
)大概是说在这个crate
里面既没有trait
的原型也没有&str
的定义,这在Rust中是禁止的!要么这样
use std::ops::Add;
#[derive(Debug)]
struct Foo {x:i32}
impl Add for Foo {
type Output = i32;
fn add(self, other: Foo) -> i32 {
self.x + other.x
}
}
要么这样
trait KK {
fn p(self);
}
impl KK for String {
fn p(self) { println!("{}", self);}
}
即,trait
或type
至少有一个要在当前的crate
中
换句话说,要想直接实现let x = "a" + "b"
是不可能了,但是可以通过一些改变来实现,那么这样行不行呢?
use std::ops::Add;
impl Add for &'static str {
type Output = String;
fn add(self, other: &'static str) -> String {
let res = self.to_string() + other;
res
}
}
fn main() {
let (x, y) = ("this", "is");
let z = x + y;
assert_eq!("thisis", z);
}
编译结果是这样
rs r.rs 101 ↵
r.rs:3:1: 10:2 error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
r.rs:3 impl Add for &'static str {
r.rs:4 type Output = String;
r.rs:5
r.rs:6 fn add(self, other: &'static str) -> String {
r.rs:7 let res = self.to_string() + other;
r.rs:8 res
...
r.rs:3:1: 10:2 help: run `rustc --explain E0117` to see a detailed explanation
error: aborting due to previous error
同样的错误!!原因同样是 This error indicates a violation of one of Rust’s orphan rules for trait implementations. The rule prohibits any implementation of a foreign trait (a trait defined in another crate) where
- the type that is implementing the trait is foreign
- all of the parameters being passed to the trait (if there are any) are also
foreign.
再看下面这个实现
”`shell angel@Chameleon ~ cat t.rs use std::ops::Add;
struct T(&‘static str);
impl Add for T { type Output = String;
fn add(self, other: T) -> String {
let T(tmp1) = self;
let T(tmp2) = other;
let res = tmp1.to_string() + tmp2;
res
}
}
fn main() { let (x, y) = (T(“this”), T(“is”)); let z = x + y;
assert_eq!("thisis", z);
} angel@Chameleon ~ rs t.rs angel@Chameleon ~ ./t angel@Chameleon ~
成功编译,并且成功运行。它只是遵守了`T(&'static str)`这个类型是在这个`crate`中,这一条规则!
---
以上只是针对两个本身就不支持`Add`的类型的实现。那么,重载原本就支持的会怎么样呢?
比如:
```rust
use std::ops::Add;
impl Add for i32 {
type Output = i32;
fn add(self, other: i32) -> i32 {
self + other
}
}
fn main() {
let (x, y) = (1, 2);
let z = x + y;
assert_eq!(3, z);
}
下面是编译的输出:
angel@Chameleon ~ rs r.rs
r.rs:3:1: 9:2 error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
r.rs:3 impl Add for i32 {
r.rs:4 type Output = i32;
r.rs:5
r.rs:6 fn add(self, other: i32) -> i32 {
r.rs:7 self + other
r.rs:8 }
...
r.rs:3:1: 9:2 help: run `rustc --explain E0117` to see a detailed explanation
r.rs:3:1: 9:2 error: conflicting implementations for trait `core::ops::Add` [E0119]
r.rs:3 impl Add for i32 {
r.rs:4 type Output = i32;
r.rs:5
r.rs:6 fn add(self, other: i32) -> i32 {
r.rs:7 self + other
r.rs:8 }
...
r.rs:3:1: 9:2 help: run `rustc --explain E0119` to see a detailed explanation
r.rs:3:1: 9:2 note: conflicting implementation in crate `core`
r.rs:3 impl Add for i32 {
r.rs:4 type Output = i32;
r.rs:5
r.rs:6 fn add(self, other: i32) -> i32 {
r.rs:7 self + other
r.rs:8 }
...
error: aborting due to 2 previous errors
这比上面的还多出了一个错误,另外个错误说的是There are conflicting trait implementations for the same type.可以看出Rust是拒绝override
的! 为什么我会尝试这个,是因为
angel@Chameleon ~ cat overload.rb
#!/usr/bin/ruby -w
class Fixnum
def +(other)
self - other
end
end
print "2 + 1 = #{2 + 1}\n"
angel@Chameleon ~ ruby overload.rb
overload.rb:4: warning: method redefined; discarding old +
2 + 1 = 1
angel@Chameleon ~
这在Ruby里面是可以的啊。。。