2016-02-25 96 views
-1

在Rust中實現一個通用的計算算法是相當麻煩的。感覺就像我正在重塑所有不在算法中的東西,而是在教會數字的共同域中。在Rust中實現泛型計算算法的正確方法是什麼?

例如,下面的拉斯特1.7作品factorial實現:

#![feature(zero_one)] 

use std::num::{One, Zero}; 
use std::ops::{Sub, Mul}; 
use std::cmp::Eq; 

fn fact<T>(n: T) -> T 
    where T: Clone + Eq + Zero + One + Mul<T, Output = T> + Sub<T, Output = T> 
{ 
    if n == T::zero() { 
     T::one() 
    } else { 
     fact(n.clone() - T::one()) * n 
    } 
} 

fn main() { 
    println!("{}", fact(10)); 
} 

是否有這樣做的任何正確的方式?有沒有討論過它呢?


大概factorial不是很好的例子,讓我們嘗試is_even

fn is_even<T>(x: T) -> bool 
    where T: std::ops::Rem<Output = T> + std::ops::Add<T, Output=T> + std::num::One + std::num::Zero + std::cmp::PartialEq 
{ 
    let two = T::one() + T::one(); 
    (x % two) == T::zero() 
} 

如果你想有一個two的東西,你必須重新實現兩項。

+2

這似乎並不像Stack Overflow可以回答的狹隘目標問題。 「我如何實現一個通用算法」是一個非常廣泛的話題。正如我寫的,你的代碼看起來像我期望的階乘的定義。 *對我來說,你的問題更多的是咆哮而不是一個善意的問題,但這可能只是我個人的解釋。 – Shepmaster

+0

@Shepmaster如果發現'factorial',那麼這個'is_even'怎麼樣? – Adam

+2

您可以通過使用[num crate](https://github.com/rust-num/num)中的特徵來減少邊界,但實現將保持不變。您如何期望is_even的通用實現看起來理想? –

回答

3

如果我想實現我is_even顯然通過實施is_divisible這是比較通用的開始:

#![feature(zero_one)] 

use std::cmp; 
use std::num; 
use std::ops; 

fn is_divisible<T>(x: T, by: T) -> bool 
    where T: ops::Rem<Output = T> + num::Zero + cmp::PartialEq 
{ 
    (x % by) == T::zero() 
} 

這似乎很容易。

然而,is_even更是把約束,這是有點長,所以讓我們跟着幹:

trait Arithmetic: 
    From<u8> + 
    cmp::PartialEq + cmp::Eq + cmp::PartialOrd + cmp::Ord + 
    ops::Add<Self, Output = Self> + ops::Sub<Self, Output = Self> + 
    ops::Mul<Self, Output = Self> + ops::Div<Self, Output = Self> + ops::Rem<Self, Output = Self> {} 

impl<T> Arithmetic for T 
    where T: From<u8> + 
      cmp::PartialEq + cmp::Eq + cmp::PartialOrd + cmp::Ord + 
      ops::Add<T, Output = T> + ops::Sub<T, Output = T> + 
      ops::Mul<T, Output = T> + ops::Div<T, Output = T> + ops::Rem<T, Output = T> 
{} 

好吧,這個特質應該將我們遮蓋。請注意,它缺少一個ops::Neg界限,因爲此界限未針對未簽名特徵實施;所以如果我們需要Neg我們必須添加它;但它很容易。

至於關於常量的問題,確實從zero向上工作你的方式是瘋了。這就是爲什麼ZeroOne特徵仍然不穩定的原因。

通用轉換特徵是convert::Fromconvert::Into,這就是人們會用到的。

因此,讓我們重新制定is_divisible,終於實現is_even

fn is_divisible<T>(x: T, by: T) -> bool 
    where T: Arithmetic 
{ 
    (x % by) == 0.into() 
} 

fn is_even<T>(x: T) -> bool 
    where T: Arithmetic 
{ 
    is_divisible(x, 2.into()) 
} 

真的,這兩個函數似乎同時仍然一般都非常清楚。

Full code here


現在,我們可以認爲,建立這個Arithmetic特點是前往is_even的長篇大論方式。它是。但是:

  • 如果你只需要is_even,顯然你很少關心,如果它需要6個邊界;這是一個一次性
  • 如果你需要NUMERICS工作的多個通用功能,然後創建這種特質和功能的小成本的事情

總之宏偉計劃可以忽略不計,它的工作原理。這真的不是那麼繁重。

相關問題