从通用上下文快速调用非通用函数 [英] Calling non generic function from generic context swift

查看:51
本文介绍了从通用上下文快速调用非通用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在理解通用函数中的匹配类型如何快速工作方面遇到问题.我不明白为什么我的代码没有编译.

I'm having issues with understanding how matching types in generic functions work in swift. I do not understand why my code is not compiling.

这就是我所拥有的:

enum LoadingState<T> {
    case idle
    case loading
    case failed(Error)
    case loaded(T)
}

private func updateInternal(_ state: Int) {
    print("=int")
}

private func updateInternal(_ state: String) {
    print("=string")
}

private func update<T>(_ state: LoadingState<T>) {
    switch state {
    case .loaded(let viewModel):
        updateInternal(viewModel)
    default:
        break
    }
}

let stateInt: LoadingState<Int> = .loaded(42)
let stateString: LoadingState<String> = .loaded(String("Hello"))

update(stateInt)
update(stateString)

我遇到以下编译错误:

error: no exact matches in call to global function 'updateInternal'

但是,如果我为 updateInternal 添加通用函数,我就能编译代码:

However if I add generic function for updateInternal I'm able to compile the code:

private func updateInternal<T>(_ state: T) {
    print("=generic")
}

,但是在运行代码时,仅在所有调用方案中都匹配此通用函数.我可以通过以下方式解决此问题:

but when running the code only this generic function is matched in all calling scenarios. I was able to resolve this issue with this:

private func updateInternal<T>(_ state: T, type: T.Type) {
    if type == Int.self {
        updateInternal(state as! Int)
    }
    else if type == String.self {
        updateInternal(state as! String)
    }
}

private func update<T>(_ state: LoadingState<T>) {
    switch state {
    case .loaded(let viewModel):
        updateInternal(viewModel, type: T.self)
    default:
        break
    }
}

但是我很确定这不是必须的,对吧?因此,我的问题是如何通过将泛型上下文中的非泛型函数作为专用函数来解决此问题

but I'm quite sure that this should not be necessary right? My question is therefore how to resolve this issue with calling non generic functions from generic context as specialized functions

推荐答案

您的代码看起来非常糟糕,就像您习惯了C ++模板编程一样(查看您的个人资料似乎可以证实我的假设).但是Swift泛型不是模板!

Your code looks an awful lot like you are used to C++ template programing (and looking at your profile seems to confirm my assumption). But Swift generics are not templates!

此功能

private func update<T>(_ state: LoadingState<T>) {
    switch state {
    case .loaded(let viewModel):
        updateInternal(viewModel)
    default:
        break
    }
}

与C ++模板不同,编译器将完全(一次)编译该函数(或至少进行类型检查).

The compiler will compile (or at least type check) this function exactly one time, unlike C++ templates.

它将检查是否可以调用通用类型为 T 的值的 updateInternal .

It will check, whether it can call updateInternal with a value of generic type T.

如何检查?它将查看 T 的约束,并尝试将 T 减小到功能之外也可以使用的最特定类型.由于您没有将 T 约束为任何类型,因此编译器仅知道 T 的所有值都将是 Any 的协变(兼容).但是您不提供任何接受 Any updateInternal 重载.

How can it check that? It will look at the constraints of T and try to reduce T to the most specific type that is also available outside of your function. Since you have not constrained T to any type, the compiler only knows that all values of T will be covariant (compatible to) Any. But you don't provide any overload of updateInternal that accepts Any.

如果您提供

private func updateInternal<T>(_ state: T) {
    print("=generic")
}

这当然可以称为,因为它实际上接受任何类型(或者换句话说,接受 Any ).

This can be called, of course, since it accepts literally any type (or, speaking differently, accepts Any).

如果您提供了

private func updateInternal(_ state: Any) {
    print("=any")
}

相反,您的代码也将编译.

instead, your code will compile too.

但是在运行代码时,在所有调用情况下仅此通用函数都匹配

but when running the code only this generic function is matched in all calling scenarios

是的,是的.但是Swift的语义不允许编译器证明或使用这一事实.(与C ++不同,每个模板实例化都会导致编译器使用提供的类型分别编译模板.)

Yeah, that's true. But the semantics of Swift don't allow the compiler to prove or use that fact. (Unlike in C++, where each template instantiation causes the compiler to separately compile the template with the provided types.)

因此,我的问题是如何通过将泛型上下文中的非泛型函数作为专用函数来解决此问题

My question is therefore how to resolve this issue with calling non generic functions from generic context as specialized functions

Swift没有专门的函数,因为再次,编译器只编译一次泛型函数.编译器无法选择正确的专业化.在Swift中,通过面向对象/动态分派(在C ++中为 virtual )可以实现相同的目的.

Swift doesn't have specialized functions because, once again, the compiler compiles the generic function only once. There's no way the compiler could select the right specialization. The same thing is achieved in Swift via object-orientation/dynamic dispatch (virtual in C++).

您可以对可以作为通用参数传递的类型提供约束.例如,这将起作用:

You can provide constraints on the type that can be passed as generic parameter. For example, this would work:

private func update<T: String>(_ state: LoadingState<T>) {
    switch state {
    case .loaded(let viewModel):
        updateInternal(viewModel)
    default:
        break
    }
}

因为现在编译器知道 T 将与String协变,所以它可以调用 updateInternal .但这当然是毫无意义的.

Because now the compiler knows that T will be covariant with String and it can call updateInternal. But it is, of course, pointless.

通常,您将定义一个协议,其中包含所需的T的所有功能(例如提供和updateInternal方法!)并将其约束为T.

You would normally define a protocol that embodies all the functionality of that T that you need (like providing and updateInternal method!) and constrain T to it.

我建议您了解有关类型约束和协议的更多信息.

I suggest you learn more about Type Constraints and Protocols.

这篇关于从通用上下文快速调用非通用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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