gpt4 book ai didi

ios - 使用开关控制流从函数推断返回类型

转载 作者:搜寻专家 更新时间:2023-11-01 06:54:11 27 4
gpt4 key购买 nike

我有一组属性/协议(protocol)(背景故事是 here ,但我认为这是多余的)

类类型如下所示:

struct AdjustmentTypes {
internal class BaseType<T>: Hashable {

static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}

typealias A = T

var hashValue: Int { return name.hashValue }

let name: String
let defaultValue: T
let min: T
let max: T
var value: T

init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}

class FloatType: BaseType<CGFloat> { }

class IntType: BaseType<Int> { }
}

我正在使用类型删除来删除类型,这样我就可以将它们存储在 Set 中,并且我构建了一些辅助方法来制作我的 Set 工具更简单:

class AdjustmentsSet {

private var adjustmentsSet: Set<AnyHashable> = []

func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}

func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}

func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}

var count: Int { return adjustmentsSet.count }
}

var adjustmentsSet = AdjustmentsSet()

我现在想做的是向我的 Set 管理类添加一些助手,以便能够检索具有正确类型的属性,例如如果我这样做:

let brightness = Brightness().make()
adjustments.get(brightness)

它应该返回 nil,但如果我返回:

adjustments.insert(brightness)
adjustments.get(brightness)

我现在应该取回值,作为它的正确类型,AdjustmentTypes.FloatType

我正在考虑使用这样的 Switch 语句:

class AdjustmentsSet {

// ...

func get(_ adjustment: AnyHashable) -> Any? {
guard let untyped = adjustmentsSet.first(where: { $0 == adjustment }) else { return nil }
switch adjustment {
case _ as AdjustmentTypes.FloatType: return untyped as! AdjustmentTypes.FloatType
case _ as AdjustmentTypes.IntType: return untyped as! AdjustmentTypes.IntType
default: return nil
}
}
}

然而,致命的缺陷当然是返回 Any,而不是预期的类型。

如何推断返回值的类型并返回正确的类型?


完整的例子,把它放到 Playground 上:

// Generic conforming protocol to AnyHashable
protocol AnyAdjustmentProtocol {
func make() -> AnyHashable
}

protocol AdjustmentProtocol: AnyAdjustmentProtocol {
associatedtype A
func make() -> A
}

struct AdjustmentTypes {
internal class BaseType<T>: Hashable {

static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}

typealias A = T

var hashValue: Int { return name.hashValue }

let name: String
let defaultValue: T
let min: T
let max: T
var value: T

init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}

class FloatType: BaseType<CGFloat> { }

class IntType: BaseType<Int> { }
}

struct AnyAdjustmentType<A>: AdjustmentProtocol, Hashable {
static func == (lhs: AnyAdjustmentType<A>, rhs: AnyAdjustmentType<A>) -> Bool {
return lhs.hashValue == rhs.hashValue
}

private let _make: () -> AnyHashable
private let hashClosure:() -> Int

var hashValue: Int {
return hashClosure()
}

init<T: AdjustmentProtocol & Hashable>(_ adjustment: T) where T.A == A {
_make = adjustment.make
hashClosure = { return adjustment.hashValue }
}
func make() -> AnyHashable {
return _make()
}
}

struct Brightness: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
}
}
struct WhiteBalance: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
}

let brightness = Brightness().make()
let whiteBalance = WhiteBalance().make()

class AdjustmentsSet {

private var adjustmentsSet: Set<AnyHashable> = []

func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}

func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}

func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}

var count: Int { return adjustmentsSet.count }
}

var adjustmentsSet = AdjustmentsSet()

最佳答案

您需要将该方法重写为泛型,并使用足够的类型信息调用它,即您需要提前知道您希望该方法返回什么类型。

我也不确定传递 AnyHashables 是否理想。没有什么能阻止您向调整集添加可散列的字符串、整数和其他随机类型。

var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert("1") // compiles just fine!

或者,您可以使用和传递您的 AdjustmentTypes 并使用通用方法重写 AdjustmentsSet 类:

class AdjustmentsSet {

private var adjustmentsSet: Set<AnyHashable> = []

func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}

func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}

func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}

func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}

var count: Int { return adjustmentsSet.count }
}

接下来,您的 make() 方法也应该是强类型的,因为您没有传递 AnyHashables。我这样实现了亮度和白平衡:

extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}

并且还利用了 Swift 中的类型别名和结构,使您的调整类型系统按照值语义运行:

struct AdjustmentTypes {

struct BaseType<T>: Hashable {

static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}

typealias A = T

var hashValue: Int { return name.hashValue }

let name: String
let defaultValue: T
let min: T
let max: T
var value: T

init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}

typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}

最后,您可以按预期使用调整集:

var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5

var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)

let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0

整个 Playground :

struct AdjustmentTypes {

struct BaseType<T>: Hashable {

static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}

typealias A = T

var hashValue: Int { return name.hashValue }

let name: String
let defaultValue: T
let min: T
let max: T
var value: T

init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}

typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}

extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}

class AdjustmentsSet {

private var adjustmentsSet: Set<AnyHashable> = []

func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}

func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}

func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}

func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}

var count: Int { return adjustmentsSet.count }
}

var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5

var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)

let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0

希望这对您有所帮助,祝您的项目顺利!

关于ios - 使用开关控制流从函数推断返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54845983/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com