【问题标题】:Generics and Constraints (`Instance method '...' requires that 'T' conform to 'Decodable'`)泛型和约束(`Instance method '...' 要求 'T' 符合 'Decodable'`)
【发布时间】:2020-07-03 08:48:31
【问题描述】:

我有一个允许使用不同类型的通用结构。我不想将整个结构限制为仅可解码项目。

修复以下错误的最佳方法是什么,我尝试仅在 T 符合 Decodable 时执行一些代码: Instance method '...' requires that 'T' conform to 'Decodable'

struct Something<T> {
    ...

    func item<T>(from data: Data) -> T? where T: Decodable {
        try? JSONDecoder().decode(T.self, from: data)
    }
    
    func getter() -> T {
        let value = ...
        
        if let value = value as? T { return value } // something simple like string
        if let data = value as? Data, T.self is Decodable { // something complex
            return item(from: data) ?? defaultValue // error is thrown here
        }
        
        return defaultValue
    }
}

如您所见,我正在检查是否符合 if 子句,但这还不足以访问受约束的方法吗? :/

【问题讨论】:

    标签: swift generics codable decodable generic-constraints


    【解决方案1】:

    对我来说,T 只需要在某些部分符合 Decodable 而不是其他部分,这对我来说毫无意义。我会将结构重写为

    struct Something<T: Decodable> {
    
        func item(from data: Data) -> T?  {
            try? JSONDecoder().decode(T.self, from: data)
        }
    
        func getter() -> T {
            let value = ...
         
            if let data = value as? Data
                return item(from: data) ?? defaultvalue
            }
    
            return defaultvalue
        }
    }
    

    【讨论】:

    • 因为可能有不符合Decodable的类型?对于其他类型,我仍然想使用相同的结构来处理它。
    • 我不认为像这样混合它是一个好主意,可能有 T 不符合 Decodable 并且有一个单独的工厂类(或工厂方法)可以创建 Something 对象不同类型的输入,如 json 数据。如果你需要支持不同类型到 T 的不同转换,我认为你的 getter 函数很快就会变得一团糟。你希望在课堂之外拥有它。
    【解决方案2】:

    首先,您应该在定义结构时将 T 限制为 Decodable。其次,您不能在内部将 T 定义为函数的泛型参数,因为它不会被编译器视为结构符合的相同 T。相反,它将被视为一个新的和不同的泛型类型约束(您只是碰巧给出了相同的名称)。这样做就足够了:

    struct Something<T: Decodable> {
      
      var defaultValue: T
      var data: Data
      
      func item(from data: Data) -> T? {
        try? JSONDecoder().decode(T.self, from: data)
      }
      
      func getter() -> T {
        item(from: data) ?? defaultValue
      }
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用扩展来定义更受约束的方法:

      struct Something<T> {
         var defaultValue: T
      
         func getter() -> T {
            return defaultValue
         }
      }
      
      extension Something where T: Decodable {
         func getter() -> T {
      
            // I'm assuming here that you have a property data: Data
            try? JSONDecoder().decode(T.self, from: data) ?? defaultValue
         }
      }
      

      目前尚不完全清楚您将如何以有意义的方式使用此类型。您的代码的构造方式,valueAny 类型。这是你的意思吗? (我猜,不是)

      在某个地方,您需要制作Something 的具体版本 - 即它将是 Something&lt;Int&gt;Something&lt;String&gt;Something&lt;SomeDecodableType&gt; - 那时 T 将是那个具体的类型,就像你可以看到,T的各个版本之间没有什么共同点,除了Any

      所以要弄清楚Something 的哪些部分真正常见。

      【讨论】:

        猜你喜欢
        • 2017-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        • 2016-11-13
        • 1970-01-01
        • 2019-02-02
        相关资源
        最近更新 更多