swift type erasure understanding, Cannot convert value of type 'AnyMapper<Payload, [Post]>' to expected element type 'AnyMapper<Payload, User>

huangapple go评论68阅读模式
英文:

swift type erasure understanding, Cannot convert value of type 'AnyMapper<Payload, [Post]>' to expected element type 'AnyMapper<Payload, User>

问题

我尝试将两个对象放入数组,但是我收到了这个错误:**无法将类型为 'AnyMapper<Payload, [Post]>' 的值转换为预期的元素类型 'AnyMapper<Payload, User>'**。有人能解释一下如何修复吗?
英文:
struct Payload {}
struct User {}
struct Post {}

protocol Mapper {
    associatedtype PayloadType
    associatedtype ResultType
    
    func map(_ payload: PayloadType) -&gt; ResultType
}

class AnyMapper&lt;P, R&gt;: Mapper {
    private var _mapClouser: (P) -&gt; R
    
    init&lt;M: Mapper&gt;(_ mapper: M) where M.PayloadType == P, M.ResultType == R {
        _mapClouser = mapper.map(_:)
    }
    
    func map(_ payload: P) -&gt; R {
        _mapClouser(payload)
    }
}

class UserMapper: Mapper {
    func map(_ payload: Payload) -&gt; User {
        return User()
    }
}

class PostsMapper: Mapper {
    func map(_ payload: Payload) -&gt; [Post] {
        return [Post(), Post(), Post()]
    }
}

let userMapper = AnyMapper(UserMapper())
let postsMapper = AnyMapper(PostsMapper())

var array: [AnyMapper] = [userMapper, postsMapper] &lt;&lt;&lt; Error: Cannot convert value of type &#39;AnyMapper&lt;Payload, [Post]&gt;&#39; to expected element type &#39;AnyMapper&lt;Payload, User&gt;&#39;

I tried to put 2 objects into array, but I get this error: Cannot convert value of type 'AnyMapper&lt;Payload, [Post]&gt;' to expected element type 'AnyMapper&lt;Payload, User&gt;'

Can someone explain to me how to fix it?

答案1

得分: 0

[Post]User 不是相同的类型。不需要一个擦除类型将它们放入同一个数组中。

var array: [任意映射器] = [UserMapper(), PostsMapper()]
英文:

[Post] and User are not the same type. You don't need an erasing type to put them into the same array.

var array: [any Mapper] = [UserMapper(), PostsMapper()]

答案2

得分: 0

AnyMapper 本身并不是一个类型。它是一个类型构造器。基本上,它是一个“函数”,它

  • 在编译时运行,
  • 以名为 PR 的参数形式接受类型,并且
  • 返回一个类型。

所以,例如如果你写 AnyMapper&lt;Payload, User&gt;,那是对类型构造器 AnyMapper 的一个编译时函数调用,传递了参数 PayloadUser。它返回一个类型,我们可以用相同的语法引用它,AnyMapper&lt;Payload, User&gt;

通常,Swift 可以推断参数类型,所以尽管你没有显式传递它们,Swift 会为你传递它们。

这就是这两行代码上发生的事情:

let userMapper = AnyMapper(UserMapper())
let postsMapper = AnyMapper(PostsMapper())

这两行代码中的每一行在推断了 PR 参数后都“调用”了 AnyMapper。我们可以使 PR 参数显式,也可以使返回的类型显式,就像这样:

let userMapper: AnyMapper&lt;Payload, User&gt; = AnyMapper&lt;Payload, User&gt;(UserMapper())
let postsMapper: AnyMapper&lt;Payload, [Post]&gt; = AnyMapper&lt;Payload, [Post]&gt;(PostsMapper())

所以现在我们可以看到你正在创建两个不同类型的对象。

接着你写了这个:

var array: [AnyMapper] = [userMapper, postsMapper]

由于你没有显式地传递类型参数给 AnyMapper,你要求 Swift 推断这些参数。它通过查看数组字面量的第一个元素 userMapper 来推断。基于此,它推断 P = PayloadR = User,所以它的行为就像你写了这样:

var array: [AnyMapper&lt;Payload, User&gt;] = [userMapper, postsMapper]

但是 postsMapper 不是一个 AnyMapper&lt;Payload, User&gt;,所以 Swift 不能编译该语句。

所有这些意味着 AnyMapper 只擦除了包装的 Mapper 的具体类型,但没有擦除它的 PayloadTypeResultType 关联类型。

不清楚你为什么想要将 userMapperpostsMapper 放在同一个数组中。它们有不同的结果类型,所以你不能通用地处理它们的结果。也许如果你解释一下为什么你认为你需要把它们都放在一个数组中,我们可以给你更好的指导。

英文:

AnyMapper by itself is not a type. It is a type constructor. Essentially, it is a “function” that

  • runs at compile time,
  • takes types as arguments named P and R, and
  • returns a type.

So for example if you say AnyMapper&lt;Payload, User&gt;, that's a compile-time function call to the type constructor AnyMapper, passing the arguments Payload and User. It returns a type, which we just refer to using the same syntax, AnyMapper&lt;Payload, User&gt;.

Often, Swift can deduce the argument types, so although you don't pass them explicitly, Swift passes them for you.

That's what's happening on these two lines:

let userMapper = AnyMapper(UserMapper())
let postsMapper = AnyMapper(PostsMapper())

Each of those lines “calls“ AnyMapper after deducing the P and R arguments. We can make the P and R arguments explicit, and also make the returned types explicit, like this:

let userMapper: AnyMapper&lt;Payload, User&gt; = AnyMapper&lt;Payload, User&gt;(UserMapper())
let postsMapper: AnyMapper&lt;Payload, [Post]&gt; = AnyMapper&lt;Payload, [Post]&gt;(PostsMapper())

So now we can see that you're creating two objects of two different types.

You next write this:

var array: [AnyMapper] = [userMapper, postsMapper]

Since you're not explicitly passing type arguments to AnyMapper, you're asking Swift to deduce the arguments. It does so by looking at the first element of the array literal, userMapper. Based on that, it deduces P = Payload and R = User, so it acts like you wrote this:

var array: [AnyMapper&lt;Payload, User&gt;] = [userMapper, postsMapper]

But postsMapper is not an AnyMapper&lt;Payload, User&gt;, so Swift can't compile that statement.

What all this means is that AnyMapper erases only the wrapped Mapper's specific type, but not its PayloadType and ResultType associated types.

It's not clear why you would want to put userMapper and postsMapper in the same array anyway. They have different result types, so you wouldn't be able to treat their results generically. Perhaps if you explain why you think you need to put them both in a single array, we can give you better guidance.

huangapple
  • 本文由 发表于 2023年2月19日 03:25:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75495841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定