类型构造函数是否实现了 Fn? [英] Does type constructor implement Fn?

查看:42
本文介绍了类型构造函数是否实现了 Fn?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定我的问题的标题是否正确,因为我不确定具体放在哪里.假设我有一个如下所示的代码:

I am not sure that the title of my question is correct since I am not sure where exactly placed. Let say I have a code which looks like:


struct MyWrapper(u64);

fn my_func<F>(f: F, n: u64) -> MyWrapper
where
    F: Fn(u64) -> MyWrapper,
{
    f(n)
}

fn main() {
    my_func(MyWrapper, 3);
}

它编译并运行,所以它看起来像 MyWrapper 实现了 trait Fn.

It compiles and works so it looks like MyWrapper implements trait Fn.

但是,我应该尝试在特征中使用它吗.

However, should I try to use it in a trait.

struct MyWrapper(u64);

trait MyTrait
where
    Self: Fn(u64) -> MyWrapper,
{
}

impl MyTrait for MyWrapper{}

我收到一个错误

16 | impl MyTrait for MyWrapper{};
   |      ^^^^^^^ expected an `Fn<(u64,)>` closure, found `MyWrapper`
   |
   = help: the trait `std::ops::Fn<(u64,)>` is not implemented for `MyWrapper`

这是一个更理论化的问题.

It was a more theoretical question.

实际上,我想要实现的是实现这样的特征

Speaking practicaly, what I am trying to achieve is to implement trait like this

我已经正确地指出我的例子不完整,所以有一个固定版本.

I have rightfully pointed out that my example is not full, so there is a fixed version.

pub enum Status {
    New,
    Cancelled,
}

struct NewTransaction(u64);

struct CancelledTransaction(u64);

fn get_by_status(id: &str, status: Status) -> Result<u64, ()> {
    Ok(3)
}

pub trait Transaction
where
    Self: std::marker::Sized,
{
    const status: Status;
    fn get(id: &str) -> Result<Self, ()>;
}

impl Transaction for NewTransaction {
    const status: Status = Status::New;
    fn get(id: &str) -> Result<Self, ()> {
        get_by_status(id, Self::status).map(Self)
    }
}

impl Transaction for CancelledTransaction {
    const status: Status = Status::Cancelled;
    fn get(id: &str) -> Result<Self, ()> {
        get_by_status(id, Self::status).map(Self)
    }
}

此代码可以编译,但正如您所看到的 - 每种类型的 Transaction 的所有实现完全相同,因此将此实现移动为默认值似乎是完全合理的.像这样

This code compiles, but as you can see - all implementations of Transaction for every type are exactly the same, so it seems totally reasonable to move this implementation as a default. Like this

pub trait Transaction
where
    Self: std::marker::Sized,
{
    const status: Status;
    fn get(id: &str) -> Result<Self, ()> {
        get_by_status(id, Self::status).map(Self)
    }
}

impl Transaction for NewTransaction {
    const status: Status = Status::New;
}

impl Transaction for CancelledTransaction {
    const status: Status = Status::Cancelled;
}

在这里,我抱怨说 Self 不能用作值.我试图通过引入条件 where Self: Fn(u32) ->自我 on trait 但它也不起作用.

And here I got a complain that Self cannot be used as a Value. I've tried to fix it by introducing a condition where Self: Fn(u32) -> Self on trait but it didn't work either.

最后,我实现了 Sven Marnach 建议的想法——添加了一个方法 new 并要求所有 struct 来实现这个方法.它看起来仍然很奇怪,因为所有结构的实现完全相同,但它有效.

In the end, I implemented the idea suggested by Sven Marnach - added a method new and required all struct to implement this method. It still looks quite strange, since the implementation is exactly the same for all structures, but it works.


pub trait Transaction
where
    Self: std::marker::Sized,
{
    const status: Status;
    fn new(n: u64) -> Self;
    fn get(id: &str) -> Result<Self, ()> {
        get_by_status(id, Self::status).map(Self::new)
    }
}

impl Transaction for NewTransaction {
    const status: Status = Status::New;
    fn new(n: u64) -> Self {
        Self(n)
    }
}

谢谢大家的回答!

推荐答案

当在一个值而不是预期的类型,而是将其视为它在预期类型的​​上下文中命名的类型.

The constructor of a tuple-like struct or enum variant is actually treated as a function name when used in a context where a value rather than a type is expected, and it is treated as the type it names in a context where a type is expected.

当调用my_func(MyWrapper, 3)时,名称MyWrapper表示一个函数,其函数项类型强制转换为函数指针类型fn(u64) ->MyWrapper.特别是,项目类型实现了特征 Fn(u64) ->MyWrapper.

When calling my_func(MyWrapper, 3), the name MyWrapper denotes a function with a function item type that coerces to the function pointer type fn(u64) -> MyWrapper. In particular, the item type implements the trait Fn(u64) -> MyWrapper.

在代码 impl MyTrait for MyWrapper {} 中,MyWrapper 表示它声明的结构类型.当在值上下文中使用时,该类型与 MyWrapper 的类型完全不同,并且它没有实现 Fn(u64) ->MyWrapper 特性.

In the code impl MyTrait for MyWrapper {}, however, MyWrapper denotes the struct type it declares. That type is completely different from the type of MyWrapper when used in a value context, and it does not implement the Fn(u64) -> MyWrapper trait.

在您的实际用例中,我认为最简单的解决方案是要求 new() 方法在类型上具有所需的原型:

In your actual use case, I believe the easiest solution is to require a new() method with the desired prototype on the type:

trait Payment {
   const status: Status;
   fn new(x: u64) -> Self;
   fn get(id: u64) -> Result<Self, Error> {
       get_by_status(Self::status, id).map(Self::new)
   }
}

Payment 的实现者只需要提供具有所需原型的 new() 方法,但会继承 get() 的默认实现>.

Implementors of Payment will only need to provide new() method with the desired prototype, but will inherit the default implementation of get().

这篇关于类型构造函数是否实现了 Fn?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆