Я хотел бы написать функцию, которая принимает только Int
или Double
и возвращает на их основе разные значения. Реальный вариант использования представляет собой SwiftUI struct: View
с несколько более сложным init()
. Если возможно, я бы хотел избежать дублирования с другим типом ввода. Как это может быть сделано?
В идеале мне бы хотелось решение, которое выглядит так:
struct MyStruct<T>: View where T is (Int | Double) { // Specifying type here is the problematic part
var value: T
var description: String
init(_ value: T) {
self.value = value
switch value {
case is Int:
description = "Integer"
case is Double:
description = "Double"
}
}
var body: some View {
Text(description)
}
Только Int
или Double
? Вы уверены, что не можете обобщить это на общий протокол, такой как SignedNumeric?
Есть как минимум два варианта:
Пользовательский фиктивный протокол, который Int
и Double
принимается в расширении.
protocol IntOrDouble {}
extension Int : IntOrDouble {}
extension Double : IntOrDouble {}
struct MyStruct<T>: View where T : IntOrDouble {
var value: T
let description: String
init(_ value: T) {
self.value = value
description = value is Int ? "Integer" : "Double"
}
var body: some View {
Text(description)
}
}
Перечисление со связанными значениями
enum IntOrDouble {
case integer(Int)
case double(Double)
}
struct MyStruct: View, CustomStringConvertible {
var value: IntOrDouble
var body: some View {
Text(description)
}
var description : String {
switch value {
case .integer(let intValue):
return "Integer \(intValue)"
case .double(let doubleValue):
return "Double \(doubleValue)"
}
}
}
value is Int ? "Integer" : "Double"
это подвержено ошибкам, потому что вы можете добавить новое соответствие к IntOrDouble
(что маловероятно, учитывая имя, но случаются и более странные вещи), что всегда будет неправильно соответствовать регистру "double"
.
В общем, дженерики используются для поддержки различных типов. Но поскольку вы хотите поддерживать только Int
и Double
, я думаю, вы можете сделать что-то вроде этого:
import SwiftUI
protocol MyType {
var typeDescription: String { get }
}
extension Int: MyType {
var typeDescription: String {
return "Integer"
}
}
extension Double: MyType {
var typeDescription: String {
return "Double"
}
}
struct MyStruct<T: MyType>: View {
var value: T
var body: some View {
Text(value.typeDescription)
}
}
#Preview {
MyStruct(value: 2) // Integer
//MyStruct(value: 2.3) // Double
}
Связано: stackoverflow.com/q/53004623/1187415