无法将协议的通用关联类型的值转换为预期的参数类型

时间:2018-07-02 15:40:32

标签: swift generics associated-types

要学习Swift泛型,我编写了一个函数来创建tableView数据源,即元素的2维(节,行)数组。 元素类型应该是通用的,并且应该使用元素的唯一值来初始化创建的数据源。

我声明了可能的元素类型采用的协议:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config>
    <domain includeSubdomains="true">mydomain.com</domain>
    <pin-set>
      <pin digest="SHA-256">@string/pin</pin>
      <pin digest="SHA-256">@string/pin_fallback</pin>
    </pin-set>
    <trustkit-config enforcePinning="true" disableDefaultReportUri="true">
    </trustkit-config>
  </domain-config>
</network-security-config>

res/values/strings.xml函数。
这里的protocol UniqueInit { associatedtype T static func uniqueInit() -> T } 是一个可变参数:给定的参数数量定义了部分的数量,参数的值定义了相应部分中的行数。

dataSource

此功能无法编译。声明

nrRowsInSection

给出错误:

static func dataSource<T: UniqueInit>(nrRowsInSection: Int...) -> [[T]] {
    var result: [[T]] = []
    for nrRows in nrRowsInSection {
        var row: [T] = []
        for _ in 0 ..< nrRows {
            row.append(T.uniqueInit())
        }
        result.append(row)
    }
    return result
}  

很明显,row.append(T.uniqueInit()) 被认为是错误的,但是为什么呢?
正确的实现方法是什么?

2 个答案:

答案 0 :(得分:2)

函数中的通用T与协议中的关联类型T不同T。在函数内部,T指的是实现协议的类型,因此,关联类型为函数内部的T.T。您的数组和返回值必须使用T.T

这也意味着您需要为函数添加一个附加参数,因为[[T.T]]返回值不足以使编译器推断T是什么类型。

这应该可以工作(我将通用参数更改为U,因为所有T令人困惑):

func dataSource<U: UniqueInit>(initializer: U.Type, nrRowsInSection: Int...) -> [[U.T]] {
    var result: [[U.T]] = []
    for nrRows in nrRowsInSection {
        var row: [U.T] = []
        for _ in 0 ..< nrRows {
            row.append(U.uniqueInit())
        }
        result.append(row)
    }
    return result
}

或者,您可以将函数定义为UniqueInit的扩展,这将消除对泛型的需求:

extension UniqueInit {
    func dataSource(nrRowsInSection: Int...) -> [[T]] {
        var result: [[T]] = []
        for nrRows in nrRowsInSection {
            var row: [T] = []
            for _ in 0 ..< nrRows {
                row.append(Self.uniqueInit())
            }
            result.append(row)
        }
        return result
    }
}

答案 1 :(得分:0)

看看下面的实现是否适合您。

protocol UniqueInit {
    static func uniqueInit() -> Self
}

func dataSource<T: UniqueInit>(nrRowsInSection: Int...) -> [[T]] {
    var result: [[T]] = []
    for nrRows in nrRowsInSection {
        var row: [T] = []
        for _ in 0 ..< nrRows {
            row.append(T.uniqueInit())
        }
        result.append(row)
    }
    return result
}

我认为上述dataSource实现中的T应该替换为UniqueInit。