基于枚举返回泛型类型

时间:2021-03-19 08:20:05

标签: swift generics enums

我正在尝试编写一个用于拆分测试的函数,该函数在传递枚举值时以通用响应进行响应。

在下面的代码中,当调用 getSplit(forFeature:) 函数时,SplitResponse 根据传入的 Feature 而变化。

protocol SplitResponse {
    associatedtype T
    func split() -> T
}

enum Feature {
    case feature1 // split test = Feature1Split
    case feature2 // split test = Bool
}

enum Feature1Split {
    case splitA
    case splitB
    case splitC
}

func getSplit(forFeature: Feature) -> SplitResponse {
    switch feature {
    case .feature1: return Feature1Response()
    case .feature2: return Feature2Response()
    }
}

struct Feature1Response: SplitResponse {
    typealias SplitResponse = Feature1Split

    func getSplit() -> SplitResponse {
        // split logic
        return .splitA
    }
}

struct Feature2Response: SplitResponse {
    typealias SplitResponse = Bool

    func getSplit() -> SplitResponse {
        // split logic
        return true
    }
}

let split1 = getSplit(forFeature: .feature1).split()

switch split1 {
    case .splitA: // doSomething
    case .splitB: // doSomethingElse
    case .splitC: // doAnotherThing
}

let split2 = getSplit(forFeature: .feature2).split()

if split2 == true {
  // doSomething
} else {
  // doSomethingElse
}

但是,我在 getSplit(forFeature:) of Protocol 'SplitResponse' can only be used as a generic constraint because it has Self or associated type requirements

上遇到错误

第一季度。我相信解决方案是根据传入的 SplitResponse 关联 Feature 类型。我该怎么做?

第 2 季度。有没有办法完全摆脱 Feature1ResponseFeature2Response 结构和 SplitResponse 协议?那么 getSplit(forFeature:) 直接返回 Feature1Split 或 Bool 吗?

4 个答案:

答案 0 :(得分:0)

不能如你所愿。您需要使用更多枚举。

extension Feature {
  enum Split {
    case feature1(Feature1Split)
    case feature2(Bool)
  }

  var split: Split {
    switch self {
    case .feature1:
      return .feature1(.splitA)
    case .feature2:
      return .feature2(true)
    }
  }
}

此语言没有像您可能希望的那样使用 split 的出色工具,此后。查看我的回答 here,了解您需要做的事情,以帮助您解决问题,如果您需要进一步的指导,请告诉我。

答案 1 :(得分:0)

您可以使用枚举:

enum Feature {
    case feature1 // split test = Feature1Split
    case feature2 // split test = Bool
}

enum Feature1Split {
    case splitA
    case splitB
    case splitC
}

enum SplitResponse {
    case feature1Response(value:Feature1Split)
    case feature2Response(value:Bool)
}

func getSplit(forFeature feature: Feature) -> SplitResponse {
    switch feature {
    case .feature1: return .feature1Response(value: .splitA) // or some other split logic
    case .feature2: return .feature2Response(value: true)    // or some other split logic
    }
}

let split1 = getSplit(forFeature: .feature1)
if case .feature1Response(let value) = split1 {
    switch value {
     case .splitA: print ("splitA")
    case .splitB: print ("splitB")
    case .splitC: print ("splitC")
    }
} else {
    print ("Ooops - Did not expect other than feature1Response")
}

let split2 = getSplit(forFeature: .feature2)
if case .feature2Response(let value) = split2 {
    if (value) {
        print ("feature2 response is true")
    } else {
        print ("feature2 response is false")
    }
} else {
    print ("Ooops - Did not expect other than feature2Response")
}

答案 2 :(得分:0)

Swift 目前不支持您尝试执行的操作。让我们看看这一行:

let split1 = getSplit(forFeature: .feature1).split()

它返回 SplitResponse 对象,但它只是一个没有具体 associatedtype 的纯协议对象。因此,当您调用您的 split(在您的 strut 对象中是 getSplit,可能是那里的拼写错误?)函数时,编译器没有机会检测到返回类型是什么。 Swift 编译器不喜欢那样,这就是您遇到的错误。

即使您的两个对象符合相同的协议,也没有有意义的方式将它们一起使用。例如,让我们考虑这种情况:

let split1 = getSplit(forFeature: .feature1).split()
let split2 = getSplit(forFeature: .feature2).split()
print(split1 == split2)

print(split1 == split2) 表达式将无效,因为编译器无法真正知道 split1split2 是什么类型。一个可以是 Bool 另一个 Feature1Split 类型,这会使表达式无效。另一方面,两者都可以是 Bool ,这将使表达式有效。但即使我们知道这是有效的,编译器也没有机会知道这一点。

答案 3 :(得分:0)

如果您不介意可选项,您也可以尝试使用类型擦除的 AnyResponse

protocol SplitResponse {
    associatedtype T
    func split() -> T
}

struct AnyResponse {
    private struct Box<T> {
        let split: () -> T
    }
    private let box: Any
    init<Response: SplitResponse>(_ response: Response) {
        box = Box(split: response.split)
    }
    
    func split<T>() -> T? {
        guard let box = box as? Box<T> else {
            return nil
        }
        return box.split()
    }
}

enum Feature {
    case feature1 // split test = Feature1Split
    case feature2 // split test = Bool
}

enum Feature1Split {
    case splitA
    case splitB
    case splitC
}

func getSplit(forFeature feature: Feature) -> AnyResponse {
    switch feature {
    case .feature1: return AnyResponse(Feature1Response())
    case .feature2: return AnyResponse(Feature2Response())
    }
}

struct Feature1Response: SplitResponse {
    func split() -> Feature1Split {
        // split logic
        return .splitA
    }
}

struct Feature2Response: SplitResponse {
    func split() -> Bool {
        // split logic
        return true
    }
}

let split1: Feature1Split? = getSplit(forFeature: .feature1).split()

switch split1 {
    case .splitA:
        print("doSomething")
    case .splitB:
        print("doSomethingElse")
    case .splitC:
        print("doAnotherThing")
case .none:
    print("nil")
}

let split2: Bool? = getSplit(forFeature: .feature2).split()

if split2 == true {
    print("doSomething")
} else {
    print("doSomethingElse")
}
相关问题