2014-07-16 1 views
9

я первоначально предположил, что вы могли бы сделать это, потому что документация (http://doc.rust-lang.org/rust.html#implementations) предлагает Вам возможность:Как вы реализуете конкретные типы в общих чертах в ржавчине?

trait Bar<T> { 
    fn ex(&self) -> T; 
} 

struct Foo { 
    y:f64 
} 

impl Bar<int> for Foo { 
    fn ex(&self) -> int { 
    return self.y.floor() as int; 
    } 
} 

impl Bar<uint> for Foo { 
    fn ex(&self) -> uint { 
    if (self.y < 0.0) { 
     return 0u; 
    } 
    return self.y.floor() as uint; 
    } 
} 

... но это не похоже на работу. Я получаю ошибки, такие как:

error: multiple applicable methods in scope 
error: expected Bar<uint>, but found Bar<int> (expected uint but found int) 
error: expected Bar<int>, but found Bar<uint> (expected int but found uint) 

Так что я подумал, возможно, Foo должен быть общим для этой работы, поэтому каждый конкретный Foo имеет собственную реализацию Бар на нем:

trait Bar<T> { 
    fn ex(&self) -> T; 
} 

struct Foo<T> { 
    y:f64 
} 

impl<T> Foo<T> { 
    fn new<U>(value:f64) -> Foo<U> { 
    return Foo { y: value } as Foo<U>; 
    } 
} 

impl Bar<int> for Foo<int> { 
    fn ex(&self) -> int { 
    return self.y.floor() as int; 
    } 
} 

impl Bar<uint> for Foo<uint> { 
    fn ex(&self) -> uint { 
    if (self.y < 0.0) { 
     return 0u; 
    } 
    return self.y.floor() as uint; 
    } 
} 

fn main() { 
    let z = Foo::new::<int>(100.5); 
    let q = Foo::new::<uint>(101.5); 
    let i:int = z.ex(); 
    let j:uint = q.ex(); 
} 

... но мой конструктор, кажется, не работает:

x.rs:11:12: 11:38 error: non-scalar cast: `Foo<<generiC#1>>` as `Foo<U>` 
x.rs:11  return Foo { y: value } as Foo<U>; 
        ^~~~~~~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

Edit: Я также попытался:

impl<T> Foo<T> { 
    fn new<U>(value:f64) -> Foo<U> { 
    let rtn:Foo<U> = Foo { y: value }; 
    return rtn; 
    } 
} 

Какие решить ошибку произнесения, но результаты в:

x.rs:32:11: 32:26 error: cannot determine a type for this expression: unconstrained type 
x.rs:32 let z = Foo::new::<int>(100.5); 
        ^~~~~~~~~~~~~~~ 

O_o ​​Я понятия не имею, что это значит.

Как вы это делаете?

ответ

6

Ошибка impl Bar<int> for Foo и impl Bar<uint> for Foo является ошибкой, потому что на данный момент разрешено только одному impl на каждый признак, введите пару (игнорируя параметры на основе). I went into more detail in this answer, включая работу с использованием вторичного признака, позволяющего сделать Foo общий (что, вероятно, не то, что вы хотите).

trait BarForFoo { 
    fn do_ex(foo: &Foo) -> Self; 
} 
impl BarForFoo for int { 
    fn do_ex(foo: &Foo) -> int { 
     foo.y.floor() as int 
    } 
}  
impl BarForFoo for uint { 
    fn do_ex(foo: &Foo) -> uint { 
     foo.y.max(0.0).floor() as uint 
    } 
} 

impl<T: BarForFoo> Bar<T> for Foo { 
    fn ex(&self) -> T { BarForFoo::do_ex(self) } 
} 

Вторая ошибка в том, что у вас есть два параметра типа T и U «в рамках» для функции new, но только с указанием одного (U). В T нужно указать в письменном виде Foo::<int>::..., однако я не думаю, что это то, что вы хотите, вместо этого, вы должны использовать T родовые в new функции:

impl<T> Foo<T> { 
    fn new(value: f64) -> Foo<T> { ... } 
} 

В фоновом режиме, компилятор должен знать конкретный тип T, поскольку реализация new может измениться:

impl<T> Foo<T> { 
    fn new<U>(value:f64) -> Foo<U> { 
    Foo { y: value + std::mem::size_of::<T>() as f64 } 
    } 
} 

, а затем Foo::<()>::new::<int>(0.0) даст y == 0.0, но Foo::<u64>::new::<int>(0.0) даст y == 8.0 ,

+0

Отличный ответ ~ Интересно, можете ли вы просто прояснить одну маленькую точку со второй части. impl Foo {fn new () -> Array } также не работает. Это все еще ошибки о неограниченном типе. Тем не менее, если я удалю новый из implix Foo {} и положил его в impl Foo <()> {}, он отлично работает. Почему это? Почему -> Array не выводит Array :: на тип возврата? ... и что это такое <()> вещь, которая заставляет ее работать? – Doug

+1

@Doug первый случай определяет новый параметр типа, также называемый 'T', тот же, что и' let a = 1; {let a = 2; } 'определяет новую переменную' a' внутри внутренней области. Дело 'Foo <()>' работает, потому что у вас тогда есть только параметр типа из 'new () -> Array ', поскольку вы указали конкретный тип (['()', aka unit] (http://doc.rust-lang.org/master/std/unit/primitive.unit.html)) для параметра типа 'Foo': он больше не является общим. Массив '->' не выводит возвращаемый тип, потому что это было бы неправильно, нет причин, по которым 'U' и' T' должны быть одинаковыми ... – huon

+0

E.g. у вас может быть 'impl Array {fn convert (& self) -> Array {...}}', который создает массив другого типа: только потому, что вы упоминаете 'Array <...>', не означает, что он имеет для соответствия 'Array <...>' в заголовке 'impl'. – huon