swift 返回基于枚举的泛型类型

k4emjkb1  于 2023-05-16  发布在  Swift
关注(0)|答案(4)|浏览(148)

我正在尝试编写一个用于分割测试的函数,当传递枚举值时,该函数将以泛型响应进行响应。
在下面的代码中,当调用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
}

但是,我在Protocol 'SplitResponse' can only be used as a generic constraint because it has Self or associated type requirementsgetSplit(forFeature:)上得到一个错误
Q1.我认为解决方案是根据传入的Feature关联SplitResponse类型。我该怎么做?
Q2.有没有办法完全摆脱Feature1ResponseFeature2Response结构体和SplitResponse协议?所以getSplit(forFeature:)直接返回Feature1Split或Bool?

ujv3wf0j

ujv3wf0j1#

如果你不介意可选的,你也可以尝试一个类型删除的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")
}
zzlelutf

zzlelutf2#

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

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,了解您需要做的事情,以帮助解决这个问题,如果您需要进一步的指导,请告诉我。

lmvvr0a8

lmvvr0a83#

你可以使用枚举:

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")
}
c9x0cxw0

c9x0cxw04#

您正在尝试的操作目前在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 s,这将使表达式有效。但即使我们知道这是有效的,编译器也没有机会知道这一点。

相关问题