簡體   English   中英

允許 Swift 函數參數為多種類型

[英]Allow Swift function parameter to be of multiple types

一個函數

func stepperValueChanged(_ myStepper: UIStepper) {
    // do stuff with myStepper
}

第二個功能

func switchValueChanged(_ mySwitch: UISwitch) {
    // do stuff with mySwitch
}

如何創建可以采用任一類型的第三個(替代)函數?

func valueChanged(_ myComponent: /* ??? UIStepper or UISwitch, but nothing else ??? */) {
    // do stuff with myComponent
}

我已經探索過使用枚舉、類型別名和協議; 這導致了許多有趣的 Stackoverflow 讀取,但沒有解決方案。

不起作用的例子

// ** DON'T COPY AND PASTE, DONT WORK!! ** //
typealias validUIComponent = UIStepper, UISwitch
// or
typealias validUIComponent = UIStepper & UISwitch
// or
enum UIComponent { case stepper(UIStepper); case _switch(UISwitch) }
// or
protocol UIComponent { }
extension UIStepper: UIComponent { }
extension UISwitch: UIComponent { }
// ** DON'T COPY AND PASTE, DONT WORK!! ** //

我為什么要這樣做? 類型檢查。 我不希望將任何其他 UI 元素傳遞給該函數。

我意識到如果 let/guard let 或某種其他形式的檢查一次在函數體中並根據需要保釋我可以,但這只會捕獲運行時而不是編譯時類型錯誤。

我也意識到我可以使用任何? 或(更好) UIControl 並根據需要向下轉型。

func valueChanged(_ myComponent: UIControl) {
    // do stuff with
    myComponent as! UIStepper
    // do stuff with
    myComponent as! UISwitch
}

但是有沒有語法/更具表現力的解決方案?

你提到了枚舉,這聽起來非常適合這個用例。 您可以明確地只要求您期望的類型,而沒有其他要求。 通過向枚舉添加屬性,您可以公開UIControl屬性以根據需要進行交互,而無需向下轉換(這通常被認為是反模式)。

enum Component {
  case `switch`(UISwitch)
  case stepper(UIStepper)
  
  var control: UIControl {
    switch self {
      case .switch(let comp):
        return comp
      case .stepper(let comp):
        return comp
    }
  }
}

然后請求一個Component作為函數的參數。

func controlValueChanged(_ myComponent: Component) {
  // Now you can use them as a generic UIControl
  let control = myComponent.control
  
  // ...or different behaviours for each element
  switch myComponent {
    case .switch(let swit):
      // use the `swit`
    case .stepper(let step):
      // use the `step`
  }
}

話雖如此,如果這些類型的實現無論如何都完全不同,那么定義兩個單獨的函數可能會更清楚。

我認為你在這里把事情復雜化了,並且沒有必要通過引入協議或新類型(枚舉)來創建任何開銷。

相反,我會通過使用多態並聲明多個具有相同簽名的函數來處理這個問題。

func controlValueChanged(_ switch: UISwitch) {
    // code…
}

func controlValueChanged(_ stepper: UIStepper) {
    // code…
}

這將使調用代碼保持整潔,並使每個函數的責任清晰。

如果兩個函數之間有一些公共代碼,則將其提取到第三個公共函數中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM