陷阱

今天又看了一遍”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里的修饰,这个循环标签适合于循环中的continuebreak,总之这个东西能够在嵌套循环中减少些代码。

那么问题来了,怎样实现 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);}
}

即,traittype至少有一个要在当前的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

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里面是可以的啊。。。