Tôi đã gặp vấn đề này khi cố gắng thêm impl Add<char> for String
vào thư viện chuẩn. Nhưng chúng ta có thể sao chép nó một cách dễ dàng, mà không cần các nhà điều hành shenanigans. Chúng tôi bắt đầu với điều này:
trait MyAdd<Rhs> {
fn add(self, rhs: Rhs) -> Self;
}
impl MyAdd<&str> for String {
fn add(mut self, rhs: &str) -> Self {
self.push_str(rhs);
self
}
}
Đủ đơn giản. Với điều này, đoạn mã sau sẽ biên dịch:
let a = String::from("a");
let b = String::from("b");
MyAdd::add(a, &b);
Lưu ý rằng trong trường hợp này, biểu thức đối số thứ hai ( &b
) có kiểu &String
. Sau đó, nó được kết hợp lại &str
và chức năng gọi hoạt động.
Tuy nhiên , chúng ta hãy thử thêm hàm ý sau:
impl MyAdd<char> for String {
fn add(mut self, rhs: char) -> Self {
self.push(rhs);
self
}
}
Bây giờ MyAdd::add(a, &b)
biểu thức trên dẫn đến lỗi sau:
error[E0277]: the trait bound `std::string::String: MyAdd<&std::string::String>` is not satisfied
--> src/main.rs:24:5
|
2 | fn add(self, rhs: Rhs) -> Self;
| ------------------------------- required by `MyAdd::add`
...
24 | MyAdd::add(a, &b);
| ^^^^^^^^^^ the trait `MyAdd<&std::string::String>` is not implemented for `std::string::String`
|
= help: the following implementations were found:
<std::string::String as MyAdd<&str>>
<std::string::String as MyAdd<char>>
Tại sao vậy? Đối với tôi có vẻ như việc cưỡng chế deref chỉ được thực hiện khi chỉ có một ứng cử viên chức năng. Nhưng điều này có vẻ sai với tôi. Tại sao các quy tắc sẽ được như vậy? Tôi đã thử xem qua các đặc điểm kỹ thuật, nhưng tôi không tìm thấy bất cứ điều gì về sự ép buộc đối số.
impl
đặc điểm áp dụng, nó có thể định hướng bằng cách chọn đối số loại được sử dụng trong đóimpl
. Trong phần hỏi đáp khác, tôi đã sử dụng khả năng này để khiến trình biên dịch (dường như) chọn mộtimpl
tại trang web cuộc gọi, đây là điều mà nó thường không thể làm được. Có lẽ trong này trường hợp đó là những gì cho phép nó để làm deref cưỡng chế. Nhưng đó chỉ là dự đoán.