2016-02-25 2 views
-1

Весьма неприятно реализовать общий алгоритм вычисления в Rust. Мне кажется, что я изобретаю все вещи не в алгоритме, а в кодемоне церковных цифр.Каков правильный способ реализации общих алгоритмов вычислений в Rust?

Например, вот реализация factorial, которая работает в Rust 1.7:

#![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 вверх безумный. Именно по этой причине черты Zero и One по-прежнему нестабильны.

Общие признаки конвертации: convert::From и convert::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 границ; это один от
  • , если вам необходимо иметь несколько обобщенных функции, работающие на числовых значениях, то небольшая стоимость создания этого признака и функции пренебрежимо мала в великой схеме вещей

Короче говоря, это работает. И это действительно не так обременительно.

Смежные вопросы