作为泛型类型的默认参数

Default parameter as generic type

我有协议和他的实现写在Swift:

protocol P {
}

struct A: P {
}

协议被用作某些函数的通用类型:

func foo<T: P>(param: T) {
}

func foo() {
    foo(param: A())
}

到目前为止一切正常。但我想将 A() 设置为给定函数的默认参数:

func foo<T: P>(param: T = A()) {
}

不幸的是,出现以下错误:

Default argument value of type 'A' cannot be converted to type 'T'.

func foo<T: P>(param: T = A() as P) {
}

,

let a: P = A()
func foo<T: P>(param: T = a) {
}

Returns:

Default argument value of type 'P' cannot be converted to type 'T'

func foo<T: P>(param: T = A() as T) {
}

Returns:

'A' is not convertible to 'T'; did you mean to use 'as!' to force downcast?

我做错了什么?问题出在哪里?

我不想像这样使用强制转换:

func foo<T: P>(param: T = A() as! T) {
}

提前致谢。

您正试图在泛型函数中强制执行非泛型默认参数:您可能应该考虑一下您要在此处实现的目标。

为了便于讨论,您 可以 在您的函数签名中包括尝试将 A() 转换为 T,但您需要将参数类型更改为可选以允许失败的转换 (nil),例如

func foo<T: P>(param: T? = (A() as? T)) { }

一个更合理的选择是——除了你的泛型函数——一个具体的非泛型函数,用于 TA 的实例(具体函数将优先于泛型函数),在这种情况下,您可以在具体函数的函数签名中包含 A() 的默认参数。例如

protocol P { }
struct A: P { }
extension Int: P { }

func foo<T: P>(param: T) { print("called generic foo") }
func foo(param: A = A()) { print("called A specific foo") }

foo()    // called A specific foo (making use of default arg)
foo(A()) // called A specific foo
foo(1)   // called generic foo

请注意,即使 A 符合 P,也会调用非泛型 fooA 可能 使用了泛型 foo):这里没有冲突,因为具体函数优先。


另一方面,如果您只希望通用函数允许在没有单个参数的情况下进行调用(即,使用默认参数),则可以在 [=20= 中包含一个简单初始化程序的蓝图],允许您将泛型类型的实例初始化为默认参数;参见

您唯一需要做的就是在协议中添加对初始化程序的要求:

protocol P {
    init()
}

struct A: P {
    var x: Int

    init() {
        x = 10
    }
}

func foo<T: P>(param param: T = T()) {
}

但是,您会遇到另一个问题。传递的参数的类型决定泛型的类型,因此您必须以其他方式指定泛型类型。