如何在生锈中实现通用特征的特定类型?

Dou*_*oug 11 rust

我最初假设您可以这样做,因为文档(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;
  }
}
Run Code Online (Sandbox Code Playgroud)

......但这似乎不起作用.我得到的错误如下:

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)
Run Code Online (Sandbox Code Playgroud)

所以我想也许Foo必须是通用的才能工作,所以每个特定的Foo都有它自己的Bar实现:

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();
}
Run Code Online (Sandbox Code Playgroud)

...但我的构造函数似乎不起作用:

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
Run Code Online (Sandbox Code Playgroud)

编辑:我也尝试过:

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

哪个解决了转换错误,但结果是:

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);
                  ^~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

O_o我不知道这意味着什么.

你怎么做到这一点?

huo*_*uon 9

impl Bar<int> for Fooimpl Bar<uint> for Foo是因为,在该时刻只能有一个错误impl时每性状允许的,对类型(忽略对该性状参数).我在这个答案中详细介绍了一些,包括使用辅助特性来避免必须制作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) }
}
Run Code Online (Sandbox Code Playgroud)

第二个错误是因为您有两个类型参数T和函数的U"范围" new,但只指定一个(U).在T通过书面指定的需求Foo::<int>::...,但我不认为这是你想要的东西,相反,你应该使用T一般的new功能:

impl<T> Foo<T> {
    fn new(value: f64) -> Foo<T> { ... }
}
Run Code Online (Sandbox Code Playgroud)

作为背景,编译器需要知道具体类型,T因为实现new可能会改变:

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

然后Foo::<()>::new::<int>(0.0)会给y == 0.0,但Foo::<u64>::new::<int>(0.0)会给y == 8.0.

  • @Doug [RFC 0048](https://github.com/rust-lang/rfcs/blob/master/text/0048-traits.md)已删除此限制,现在允许多个(特征,类型)对当类型参数不同时. (3认同)