将泛型类型传递给具有泛型约束的函数

时间:2021-07-18 11:08:56

标签: ios swift generics swift-protocols

我有一个关联类型的协议

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 对关联类型的硬依赖,我会说它工作正常,这是尽可能避免第三方依赖的原因之一。< /p>

3 个答案:

答案 0 :(得分: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("")

答案 1 :(得分:0)

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

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

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

}

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

答案 2 :(得分:0)

在 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){
}