2015-03-21 14 views
14

Tôi đang cố gắng thực hiện một chức năng chung trong Rust, nơi yêu cầu duy nhất cho đối số là phép tính nhân cần được xác định. Tôi đang cố gắng để thực hiện một "quyền lực" chung chung, nhưng sẽ đi với một cube chức năng đơn giản để minh họa cho vấn đề:Yêu cầu thực hiện Mul trong chức năng chung

use std::ops::Mul; 

fn cube<T: Mul>(x: T) -> T { 
    x * x * x 
} 

fn main() { 
    println!("5^3 = {}", cube(5)); 
} 

Khi biên soạn tôi nhận được lỗi này:

error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output` 
--> src/main.rs:4:5 
    | 
4 |  x * x * x 
    |  ^^^^^^^^^ 
    | 
    = note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output` 

gì này có nghĩa là ? Tôi đã chọn đặc điểm sai? Làm cách nào tôi có thể giải quyết vấn đề này?

Trả lời

21

Hãy phá vỡ ví dụ của bạn một chút:

fn cube<T: Mul>(x: T) -> T { 
    let a = x * x; 
    let b = a * x; 
    b 
} 

các loại ab là gì? Trong trường hợp này, loại a<T as std::ops::Mul>::Output - âm thanh quen thuộc với thông báo lỗi? Sau đó, chúng tôi đang cố gắng nhân loại đó bằng cách x một lần nữa, nhưng không có đảm bảo rằng Output có thể được nhân với bất cứ điều gì!

Hãy làm những điều đơn giản nhất và nói rằng T * T nhu cầu dẫn đến một T:

fn cube<T: Mul<Output = T>>(x: T) -> T { 
    x * x * x 
} 

Thật không may, điều này sẽ cho hai lỗi tương tự:

error[E0382]: use of moved value: `x` 
--> src/lib.rs:6:9 
    | 
6 |  x * x * x 
    |  - ^value used here after move 
    |  | 
    |  value moved here 
    | 
    = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait 

Đó là bởi vì Mul trait takes arguments by value, vì vậy chúng tôi thêm Copy để chúng tôi có thể sao chép các giá trị.

Tôi cũng chuyển sang mệnh đề where như tôi thích nó tốt hơn và đó là khó sử dụng để có nhiều inline:

fn cube<T>(x: T) -> T 
where 
    T: Mul<Output = T> + Copy 
{ 
    x * x * x 
} 
11

Các ràng buộc T: Mul không có nghĩa là kết quả của các nhà điều hành nhị phân cũng là loại T. Loại kết quả là một loại liên kết được liên kết của đặc điểm này: Output.

Vấn đề khác là tại một thời điểm nào đó, các đặc điểm của nhà điều hành chuyển từ chuyển giới thiệu sang giá trị truyền qua. Trong mã chung, điều này có thể là một chút đau ở mông (ít nhất là bây giờ) bởi vì các toán tử này tiêu thụ toán hạng của chúng trừ khi bạn cũng yêu cầu các loại là Copy.

Chỉ để hoàn thành (trong trường hợp bạn không muốn yêu cầu Copy), hãy để tôi thêm một số thông tin về hướng thay thế có thể có.

Vì lợi ích của mã chung, tác giả của "kiểu dữ liệu" được khuyến khích để cung cấp thêm không tốn triển khai của những đặc điểm điều hành để bạn không cần Copy hoặc Clone. Ví dụ, các thư viện chuẩn đã cung cấp triển khai như sau:

f64 implements Mul< f64> 
f64 implements Mul<&f64> 
&f64 implements Mul< f64> 
&f64 implements Mul<&f64> 

với nhau thực hiện có f64 như Output loại.Nhưng việc sử dụng các đặc điểm này trực tiếp không đẹp:

fn cube<T>(x: &T) -> T 
    where for<'a> T: Mul<&'a T, Output = T>, 
      for<'a,'b> &'a T: Mul<&'b T, Output = T> 
{ 
    x * x * x 
} 

Cuối cùng, chúng ta có thể nhận được một số đặc điểm mức cao hơn (hơi) sẽ giảm tiếng ồn. Ví dụ: T: Mul2 có thể ngụ ý T: Mul<T> + Mul<&T>&T: Mul<T> + Mul<&T>. Nhưng tại thời điểm viết bài này, trình biên dịch Rust dường như không thể xử lý được điều này. Ít nhất tôi không thể biên dịch thành công mã sau đây:

use std::ops::Mul; 

pub trait Mul2 where 
    Self: Mul<Self, Output=Self>, 
    Self: for<'a> Mul<&'a Self, Output=Self>, 
    for<'a> &'a Self: Mul<Self, Output=Self>, 
    for<'a,'b> &'a Self: Mul<&'b Self, Output=Self> {} 

impl<T> Mul2 for T where 
    T: Mul<T, Output=T>, 
    T: for<'a> Mul<&'a T, Output=T>, 
    for<'a> &'a T: Mul<T, Output=T>, 
    for<'a,'b> &'a T: Mul<&'b T, Output=T> {} 

fn cube<T: Mul2>(x: &T) -> T { 
    x * x * x 
} 

fn main() { 
    let c = cube(&2.3); 
    println!("Hello, world! {}", c) 
} 

Tôi nghĩ rằng mọi thứ sẽ cải thiện trong lĩnh vực này. Hiện tại, khả năng thực hiện chung các thuật toán số trong Rust là không tốt như tôi mong muốn.

+0

Bạn cũng có thể giải thích (hoặc chỉ đưa ra một liên kết) ký hiệu "ở đâu", tôi chưa từng thấy nó trước đây. –

+0

trong đó các mệnh đề là cách tổng quát hơn để hạn chế các tham số chung. Chúng đã được giới thiệu qua https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md – sellibitze

+0

Ký hiệu 'for <'a> 'được giới thiệu trong RFC 387: https://github.com /rust-lang/rfcs/blob/master/text/0387-higher-ranked-trait-bounds.md. –

Các vấn đề liên quan