当前位置: 首页 > 面试题库 >

向扩展中的通用参数添加约束

伯茂才
2023-03-14
问题内容

我有这个功能:

func flatten<Key: Hashable, Value>(dict: Dictionary<Key, Optional<Value>>) -> Dictionary<Key, Value> {
    var result = [Key: Value]()
    for (key, value) in dict {
        guard let value = value else { continue }
        result[key] = value
    }
    return result
}

如您所见,它将[Key: Value?]字典转换成一个字典[Key: Value](没有可选的)。

我只想为Dictionary值是Optional任何类型的类使用新方法扩展该类,但是我无法为字典的通用参数添加约束。

这是我尝试的:

extension Dictionary where Value: Optional<Any> {
    func flatten() -> [Key: Any] {
        var result = [Key: Any]()
        for (key, value) in self {
            guard let value = value else { continue }
            result[key] = value
        }
        return result
    }
}

但失败并显示错误:

Type 'Value' constrained to non-protocol type 'Optional<Any>'

问题答案:

在Playground中尝试以下代码:

// make sure only `Optional` conforms to this protocol
protocol OptionalEquivalent {
  typealias WrappedValueType
  func toOptional() -> WrappedValueType?
}

extension Optional: OptionalEquivalent {
  typealias WrappedValueType = Wrapped

  // just to cast `Optional<Wrapped>` to `Wrapped?`
  func toOptional() -> WrappedValueType? {
    return self
  }
}

extension Dictionary where Value: OptionalEquivalent {
  func flatten() -> Dictionary<Key, Value.WrappedValueType> {
    var result = Dictionary<Key, Value.WrappedValueType>()
    for (key, value) in self {
      guard let value = value.toOptional() else { continue }
      result[key] = value
    }
    return result
  }
}

let a: [String: String?] = ["a": "a", "b": nil, "c": "c", "d": nil]
a.flatten() //["a": "a", "c": "c"]

因为您不能在where协议扩展的子句中指定确切的类型,所以可以准确检测到该Optional类型的一种方法是使OptionalUNIQUELY符合协议(例如OptionalEquivalent)。

为了获得的包装值类型Optional,我WrappedValueType在自定义协议中定义了typealias
OptionalEquivalent,然后对Optional进行了扩展,将assgin设置WrappedWrappedValueType,然后可以在flatten方法中获取类型。

注意,该sugarCast方法只是将to强制转换Optional<Wrapped>Wrapped?(这是完全相同的),以启用用法guard语句。

更新

感谢Rob Napier的评论,我简化并重命名了sugarCast()方法,并重命名了协议以使其更易于理解。



 类似资料:
  • 所以我试图写一个函数,它有一个泛型,它扩展了一个特定的对象,从而约束了它。接下来,我想将这个泛型与参数的定义一起使用,以生成一个新的“增强”参数。这一切都很好,但一旦我想引入一个默认值的参数TypeScript抱怨如下消息(这在操场上的一些不同的变化): 功能: 错误: 类型“{foo:string;}”不可分配给类型“T” 编译器警告我,我可能想使用foo,实际上我做到了。是简单地不可能以这种方

  • 问题内容: 我想扩展以增加对新协议的一致性-但仅适用于其元素本身符合特定协议的数组。 更笼统地说,我想让带有类型参数的类型(无论是协议类型还是具体类型)仅在类型参数与某些约束匹配时才实现协议。 从Swift 2.0开始,这似乎是不可能的。有什么我想念的方式吗? 例 假设我们有以下协议: 我们可以扩展现有的类型来实现它: 我们还可以扩展实现其所有元素时的实现: 在这一点上,类型本身应该实现,因为它符

  • 问题内容: 我是这些泛型类型的新手。在下面的代码中,我创建了一个方法,该方法接受扩展了“字符串”的项目列表。 我的问题?-当列表可以分配一个新列表时,为什么不能添加字符串“ test” …这给了我一个编译错误。 问题答案: 因为与此处无关的不是运行时类型。仍然是类型,您刚巧将其分配给。考虑一下: 编译器无法确定其是否有效-它仅基于的编译时类型进行决策。 请注意,实际上没有任何扩展,这是一个类。

  • 我试图在下面的填充()方法中填充一个列表,使用泛型来放松类型参数的限制,但我一直出错 类型列表中的add(int,capture#2-of?extends Number)方法不适用于参数(int) 当我尝试用编译器修复它时,它会自动用null填充列表。请问我该如何解决这个问题:

  • 问题内容: 是否可以在向其添加一些参数数据的同时将请求转发给另一个控制器?我尝试添加到ModelMap中,但是它似乎不存在问题。我正在做类似的事情: 我能想到的唯一其他方法是将参数放在会话上,然后将其弹出目标控制器。 问题答案: 最简单的方法是将数据添加到请求中。 由于这是转发,因此将相同的请求传递到服务器内的不同处理程序。 作为示例,让我们从两个控制器的简单设置开始,一个转发到另一个: 添加数据

  • 问题内容: 在使用AJAX调用的Web应用程序中,我需要提交一个请求,但要在URL的末尾添加一个参数, 寻找一种JavaScript函数,该函数解析URL并查看每个参数,然后添加新参数或更新值(如果已经存在)。 问题答案: 您需要调整的基本实现如下所示: 这大约是正则表达式或基于搜索的解决方案的两倍,但是这完全取决于查询字符串的长度和任何匹配项的索引 我为完成测试而基准的慢速正则表达式方法(慢了大