【问题标题】:Passing a generic type to a function with generic constraint将泛型类型传递给具有泛型约束的函数
【发布时间】:2021-07-18 11:08:56
【问题描述】:

我有一个带有关联类型的协议

protocol ProtocolA {
  associatedType someType
}

现在我有两个通用函数

func funcA<someType>(_ data:someType) {
    funcB(data) // cannot call
}

func funcB<someType:ProtocolA>(_ data:someType) {

}

我一直在尝试从 funcA 调用 funcB,但它不起作用我收到错误消息

Instance method 'funcB' requires that 'someType' conform to 'ProtocolA'

现在我知道 funcA 中的通用类型符合 ProtocolA 的事实。无论如何也要确保编译器也知道它吗?

我无法更改 funcA 方法声明以放置通用约束,因为这是另一个协议的要求。

我已经尝试在funcA中使用some关键字

var obj : some ProtocolA = data

但是我得到了错误

Property declares an opaque return type, but cannot infer the underlying type from its initializer expression

简而言之,无论如何我都可以在不更改 funcA 签名的情况下从 funcA 调用 funcB,但是可以将 funcB 签名更改为所需的任何内容

****编辑*****添加更多信息

funcA被protocl调用

protocol CommonService {
    func funcA<ModelType>(_ data:ModelType)
}

class CommonServiceImpl : CommonService {
    func funcA<someType>(_ data:someType) {
        funcB(data) // cannot call
    }

    func funcB<someType:ProtocolA>(_ data:someType) {
        //SomeCode here required that someType must implement ProtocolA
    }
}

ProtocolA 包含在无法更改的第三方 pod 中。

*******编辑***********我是如何解决这个问题的

感谢@Mojtaba Hosseini 的回答,我对如何解决我的问题有了一个非常好的想法。

我只是在 CommonServiceProtocol 中编写了一个重载函数

protocol CommonService {
    func funcA<ModelType>(_ data:ModelType)
    func funcA<ModelType>(_ data:ModelType) where ModelType:ProtocolA
}

class CommonServiceImpl : CommonService {
    func funcA<someType>(_ data:someType) {
        funcB(data) // cannot call
    }

    func funcA<someType>(_ data:someType) where ModelType:ProtocolA {
        funcB(data) // can be called
    }

    func funcB<someType:ProtocolA>(_ data:someType) {
        //SomeCode here required that someType must implement ProtocolA
    }
}

我的意思是这不是一个完美的解决方案,但考虑到在第三方 pod 中使用 ProtocolA 对相关类型的硬依赖,我会说它工作正常,这是尽可能避免第三方依赖的原因之一。

【问题讨论】:

  • 您能分享一下您是如何调用 funcA 的吗?您传递的协议类型和协议定义是什么?
  • @NikhilJain 添加了更多信息
  • 更不用说编译器了,你甚至无法说服 me funcA 中的 someType 必须符合 ProtocolA。如果我有class A {},然后有CommonServiceImpl().funcA(A())怎么办?

标签: ios swift generics swift-protocols


【解决方案1】:

有什么方法可以确保编译器也知道它吗?

您必须为funcA 实现重载并对其进行约束:

func funcA<someType>(_ data: someType) {
    /* funcB(data) */ cannot call
    print("Not detected")

}

func funcA<someType>(_ data: someType) where someType: ProtocolA {
    funcB(data) // can call ✅
    print("Detected")
}

所以调用funcA("") 将导致Not detected 但是符合协议并调用相同的函数会导致Detected

// extension String: ProtocolA { typealias someType = String } // uncomment to see
funcA("")

【讨论】:

  • 我尝试了这种技术,但我的代码中的 CommonServiceImpl 仍在调用第一个重载函数 print("not detected")
  • 我的意思是我的 CommonService 协议中只有第一个签名的方法,为什么要调用重载函数?
  • 也许你应该公开更多代码,因为我已经测试过符合和不符合的类型,我没有发现任何问题
  • 请参阅编辑。嘿,非常感谢你的天才想法给了我我的解决方案。谢谢你拯救我的一天:)
【解决方案2】:

根据您的要求,我认为您可以将funcB 的签名与funcA 匹配。参考以下代码:

func funcA<someType>(_ data:someType) {
    funcB(data) 
}

func funcB<someType>(_ data:someType) {

}

如上代码所示,可以去掉funcB中someType的类型约束。

【讨论】:

  • 问题是funcB中有someCode要求funcB中的someType符合ProtocolA
【解决方案3】:

在 functionB 中只需添加一个参数,该参数将告诉编译器您期望的类型,如果您真的想确定该类型是您的协议,请添加一个检查:

func transform<T>( data : T ){
guard let  data = data as? Monster else {
        print("data is not a monster type")
        return
    }
intoMonster(Monster.self, data: data)
}

func intoMonster<T> (_ type : T.Type , data : T){
}

【讨论】:

  • 问题是我的示例中的 ProtocolA 在第三方 Pod 中并使用 associatedType 这意味着每当我尝试通过“as”检查时,我都会收到错误“Protocol 'ProtocolA' can only be used as一个通用约束,因为它具有 Self 或关联的类型要求”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多