我的目标是让这段代码的最后两行编译,最后一个断言传递:
struct State {
string: String
}
impl State {
fn string<F: FnMut(String) -> String>(mut self, mut f: F) -> Self {
self.string = f(self.string);
self
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
// let state = state.string(String::from("baz"));
// assert_eq!(state.string, "baz");
}
我认为这对于特征和专业化是可能的,但是以下代码:
#![feature(specialization)]
trait Get<T> {
fn get(self, old: T) -> T;
}
impl<T> Get<T> for T {
default fn get(self, _: T) -> T {
self
}
}
impl<T, F> Get<T> for F where F: FnMut(T) -> T {
fn get(mut self, old: T) -> T {
self(old)
}
}
struct State {
string: String
}
impl State {
fn string<G: Get<String>>(mut self, g: G) -> Self {
self.string = g.get(self.string);
self
}
}
抛出此错误(live):
error[E0119]: conflicting implementations of trait `Get<_>`:
--> <anon>:13:1
|
13 | impl<T, F> Get<T> for F where F: FnMut(T) -> T {
| ^
|
note: conflicting implementation is here:
--> <anon>:7:1
|
7 | impl<T> Get<T> for T {
| ^
error: aborting due to previous error
所以我的问题是,为什么Get的第二个impl不是比第一个更具“特定”,并且在当前稳定或每晚Rust中有什么方法可以使我的原始代码工作?
编辑:我知道只为一种类型实现特征是可行的,但我想要任何类型的通用解决方案,因为我希望能够将它用于结构的任意字段。
答案 0 :(得分:6)
对于您的具体问题,您不需要专业化:
struct State {
string: String,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing
{
self.string = f.thing(self.string);
self
}
}
trait Thing {
fn thing(&mut self, s: String) -> String;
}
impl Thing for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
}
您可能要求FnOnce
或实施&str
的特征。现在,String
的分配没有被使用,导致一些效率低下。
然后,您可以多次为有趣的类型实现特征:
struct State {
string: String,
vec: Vec<u8>,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing<String>
{
self.string = f.thing(self.string);
self
}
fn vec<F>(mut self, mut f: F) -> Self
where F: Thing<Vec<u8>>
{
self.vec = f.thing(self.vec);
self
}
}
trait Thing<T> {
fn thing(&mut self, s: T) -> T;
}
impl Thing<String> for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing<String> for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
impl Thing<Vec<u8>> for Vec<u8> {
fn thing(&mut self, _s: Vec<u8>) -> Vec<u8> {
self.clone()
}
}
impl<F> Thing<Vec<u8>> for F
where F: FnMut(Vec<u8>) -> Vec<u8>
{
fn thing(&mut self, s: Vec<u8>) -> Vec<u8> {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo"), vec: vec![1] };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
assert_eq!(state.vec, [1]);
let state = state.vec(|mut old: Vec<u8>| {
old.push(2);
old
});
assert_eq!(state.vec, [1, 2]);
let state = state.vec(vec![3]);
assert_eq!(state.vec, [3]);
}
我相信重复可以由宏处理:
macro_rules! thing {
($t: ty) => {
impl Thing<$t> for $t {
default fn thing(&mut self, _val: $t) -> $t {
self.clone()
}
}
impl<F> Thing<$t> for F
where F: FnMut($t) -> $t
{
fn thing(&mut self, val: $t) -> $t {
(self)(val)
}
}
}
}
thing!(String);
thing!(Vec<u8>);
答案 1 :(得分:4)
专业化在这里不起作用,因为专业化仅适用于链。也就是说,存在满足impl
impl<T, F> Get<T> for F where F: FnMut(T) -> T
但不是
impl<T> Get<T> for T
所以后者不能专门化前者。
解决此问题的最简单方法是只编写GetString
特征而不是Get<T>
特征;这样你就不必考虑对这种malarkey的专业化了。