【问题标题】:Default value for optional generic parameter in Swift functionSwift 函数中可选泛型参数的默认值
【发布时间】:2015-02-11 15:31:15
【问题描述】:

是否可以给可选的泛型参数一个默认值?

我正在尝试做这样的事情:

func addChannel<T>(name: String, data: T? = nil) -> Channel {

}

let myChannel = addChannel("myChannelName")

但我收到一个错误提示

Argument for generic parameter 'T' could not be inferred

这只是我试图做的事情是不可能的吗?

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    以你的方式是不可能的。仅给出上面的代码,T 是什么类型?正如它所说,编译器无法弄清楚(我也不知道,而且我假设您也无法弄清楚,因为数据不存在)。

    具体问题的解决方案是重载而不是使用默认值:

    func addChannel<T>(name: String, data: T?) -> Channel { ... }
    
    func addChannel(name: String) -> Channel { ... }
    
    let myChannel = addChannel("myChannelName")
    

    但它提出了你在这里做什么的问题。你会认为Channel 应该是Channel&lt;T&gt;。不然你用data做什么?如果不求助于Any(你应该强烈避免),很难看出你的函数除了忽略data之外还能做什么。

    使用Channel&lt;T&gt;,您可以只使用默认值,但您必须提供类型:

    func addChannel<T>(name: String, data: T? = nil) -> Channel<T> { ... }
    let myChannel: Channel<Int> = addChannel("myChannelName")
    

    否则编译器不会知道你正在制作什么样的通道。

    (更新 ~ Swift 5.2)

    有时您想要T 的默认类型。你可以通过超载来做到这一点。例如,您可能希望默认类型为Never。在这种情况下,您将添加这样的重载:

    func addChannel<T>(name: String, data: T? = nil) -> Channel<T> { ... }
    func addChannel(name: String) -> Channel<Never> { 
        addChannel(name: name, data: Optional<Never>.none)
    }
    

    这样,您可以进行更简单的调用:

    let myChannel = addChannel(name: "myChannelName") // Channel<Never>
    

    【讨论】:

    • 好吧,这是有道理的——我只是误解了如何使用泛型。我的用例是 data 可以是任何类型的 Dictionary、Int 或 String,也可以是 nil。这样做的首选方法是创建data: AnyObject? = nil,然后检查函数内的数据类型吗?
    • 首选的方法不是“任何类型的 Dictionary、Int 或 String”。确定它到底是什么类型。这可能是一个“数据”类型,可以包含其中任何一个。您将其实现为具有关联数据的枚举。这样您就可以确保收到您所期望的,而不仅仅是“AnyObject”。当您开始获取 AnyObject 时?进入您的系统,根据我的经验,事情进展得很快。即使不考虑设计问题,编译器也讨厌它。
    • 有关枚举的更多信息,它是 Swift 中的一种键类型,请参阅developer.apple.com/library/prerelease/ios/documentation/Swift/…
    • 如果你必须桥接到 ObjC 并且不能使用关联的数据,你仍然应该把它包装到一个类中,这个类只能用你期望的东西来初始化。仅当您的字面意思是“我不在乎;给我任何东西”时才使用 AnyObject。
    • 使用枚举会怎样?我似乎无法让它工作。更新不用担心,我已经知道了
    【解决方案2】:

    我遇到了同样的问题。虽然传统上无法使用通用默认值(完全不考虑参数),但我更喜欢以下实现重载:

    let myChannel=addChannel("myChannelName", data: Optional<Any>.none)
    

    【讨论】:

      【解决方案3】:

      我使用现有答案的组合,这样我既可以在没有可选参数的情况下调用该函数,又可以避免两次执行该函数。

      func addChannel(name: String) -> Channel {
          addChannel(name: name, data: Optional<Any>.nil)
      }
      func addChannel<T>(name: String, data: T? = nil) -> Channel {
          ...
      }
      

      如上所述,您应该避免使用Any。就我而言,我知道TEncodable,所以我使用这个:

      struct DefaultEncodable: Encodable {}
      
      func function1(name: String) {
          addChannel(name: name, data: Optional<DefaultEncodable>.nil)
      }
      func function1<T: Encodable>(name: String, data: T? = nil) {
          ...
      }
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-24
        • 1970-01-01
        • 2017-06-20
        • 2021-05-29
        • 2018-02-18
        • 1970-01-01
        • 2011-09-20
        相关资源
        最近更新 更多