gpt4 book ai didi

rust - 允许函数接受 `T` 或任何 `FnMut(T) -> T`

转载 作者:行者123 更新时间:2023-11-29 07:42:47 25 4
gpt4 key购买 nike

我的目标是编译此代码的最后两行并通过最后一个断言:

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");
}

我认为这可以通过 traits 和 specialization 来实现,但是下面的代码:

#![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 的第二个实现不比第一个实现更“具体”,并且在当前的稳定版或夜间 Rust 中有什么方法可以让我的原始代码工作吗?

编辑:我知道只为一种类型实现特征是可行的,但我想要一个适用于任何类型的通用解决方案,因为我希望能够将其用于结构的任意字段。

最佳答案

对于您的具体问题,您不需要特化:

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>);

关于rust - 允许函数接受 `T` 或任何 `FnMut(T) -> T`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38811099/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com