如果嵌套,如何为自定义类型定义 flatten() 方法?

问题描述 投票:0回答:1

为了学习,我正在编写自己的函子实现。从功能角度来看,它没有任何意义,但它是学习该语言如何工作以及如何用它实现更复杂结构的好方法。但我陷入了如何实现

flatten
函数的困境,我想采用可能的内部包装层并将其删除。我的实现是

#[derive(Debug)]
enum Functor<T> {
  Functor(T),
}

type MapFn<T, S> = dyn Fn(T) -> S;

impl<T> Functor<T> {
    fn map<S>(self, operation: &MapFn<T, S>) -> Functor<S> {
      use Functor::Functor;

      match self {
          Functor(value) => Functor::<S>(operation(value))
      }
    }

    fn unwrap(self) -> T {
      use Functor::Functor;

      match self {
          Functor(value) => value
      }
    }

    fn flatten(self) -> Functor<T> {
      use Functor::Functor;

      // TODO: now just returns same instance
      // if the type inside is another functor, should "peel" one layer off,
      // otherwise if just value of <T>, should return self
      self
    }
}

编译器确实理解包装的类型,例如

unwrap
在以下代码中工作得很好

let fff = Functor(Functor(123));
println!("The value from wrapped functor is {:?}", fff.unwrap().unwrap())

我只是不知道如何实现这一点,以便编译器对这些类型感到满意。我尝试研究

Option
Result
等核心类型中类似函子的源代码,但它们的操作方式不同。例如,
Option
使用匹配来检查
None

我在网上找到的用于解构包装类型的示例往往具有内部带有枚举的结构,但这里的类型是相同的,但具有不同的泛型参数,因此例如编译器不会传递类似的内容

fn flatten(self) -> Functor<T> {
      use Functor::Functor;

      match self {
          Functor(Functor(T)) => ...,
      }
}

我得到的只是不匹配的类型。

generics rust
1个回答
2
投票

对于

Option
类型,
flatten
函数是在
Option<Option<T>>
类型上实现的,因此对于您的自定义函子,您将有一个单独的
impl
块,如下所示,以指示此方法仅适用于
Functor
另一个
Functor
的内部类型:

impl<T> Functor<Functor<T>> {
    fn flatten(self) -> Functor<T> {
        use Functor::Functor;
        match self {
            Functor(val) => val,
        }
    }
}

这告诉编译器内部类型也是

Functor
,因此它知道它可以解构为
Functor(Functor(val))

这只允许一次展平一层,与

Option
类型相同。

© www.soinside.com 2019 - 2024. All rights reserved.