2015-09-19 3 views
1

Я пытаюсь реализовать either функции, которая принимает два родовых контейнер и возвращать либо из них:Функция, возвращать либо из двух дженерик

func either<A,B>(a: Container<A>, b: Container<B>) -> ?either Container<A> or Container<B>? { 
    // choose any of container 
    return chosen 
} 

Похоже, мне нужен протокол, который Контейнер должен соответствует, так что мой тип возврата either должен быть этого протокола. Правильно ли это решение?

protocol ContainerProtocol 
struct Container<T>: ContainerProtocol 

func either<A: ContainerProtocol, B:ContainerProtocol, C:ContainerProtocol>(a: A, b: B) -> C { 
    // choose any of container 
    return chosen 
} 

UPDATE

нормально, так что я реализовал EitherContainer перечисления и окончательный код выглядит следующим образом:

struct Container<T>: Unique { 
    typealias UnderlyingObject = T 
    var object: UnderlyingObject 
    var uniqueId: String 
} 

enum EitherContainer<A,B> { 
    case a(container: Container<A>) 
    case b(container: Container<B>) 
} 

func wrappedInput<A,B>(wra: Container<A>, wrb: Container<B>, paramClosure: (Container<A>, Container<B>) -> EitherContainer<A,B>) -> EitherContainer<A,B> { 
    //do some work here 
    return paramClosure(wra, wrb) 
} 

func rawInput<A, B>(a: A, b: B) -> Any { 
    let wrappedA = Container(object: a, uniqueId: "a") 
    let wrappedB = Container(object: b, uniqueId: "b") 
    let wrappedRes = wrappedInput(wrappedA, wrb: wrappedB) { 
     (a1: Container, a2: Container) -> EitherContainer<A,B> in 
     // do some work here 
     return EitherContainer.a(container: a1) 
    } 
    var rawRes: Any 
    switch wrappedRes { 
    case .a(let container): 
     rawRes = container.object 
    case .b(let container): 
     rawRes = container.object 
    } 
    return rawRes 
} 

что беспокоит меня сейчас, Any тип, который закрывает компилятор но для меня похож на слабый костыль. Снова такая же проблема rawInput<A, B>(a: A, b: B) -> Any. rawInput должен возвращать A или B, но вместо этого я вынужден использовать Any. Должен ли я добавить еще одно перечисление для необработанных параметров? Есть предположения?

+0

Ваше решение, безусловно, работает. Другим подходом является реализация типа «перечисление Либо » с двумя случаями, соответствующими каждой возможности. Затем вы можете «переключиться» на возвращаемое значение и получить выбранный контейнер. Таким образом, ваша информация о типе не будет потеряна через эту функцию. –

+0

@Peter yea, enum solution довольно аккуратно –

ответ

2

Традиционный Either типа выглядит следующим образом:

enum Either<A, B> 
{ 
    case Left(A) 
    case Right(B) 
} 

и является более полезным, поскольку оно не ограничивается вашей Container типа.
(Either является "канонической" тип сумма.)

Он будет использоваться как это:

func wrappedInput<A, B> (
    a : Container<A>, 
    b: Container<B>, 
    paramClosure: (Container<A>, Container<B>) -> Either<Container<A>,Container<B>> 
    ) -> Either<Container<A>, Container<B>> 
{ 
    return Either.Left(a) // Dummy 
} 

func rawInput<A, B>(a: A, b: B) -> Either<A,B> { 
    let wrappedA = Container(object: a, uniqueId: "a") 
    let wrappedB = Container(object: b, uniqueId: "b") 
    let wrappedRes = wrappedInput(wrappedA, b: wrappedB) { 
     (a1: Container, a2: Container) -> Either<Container<A>, Container<B>> in 
     // do some work here 
     return Either.Left(a1) 
    } 

    switch wrappedRes { 
    case .Left(let container): 
     return Either.Left(container.object) 
    case .Right(let container): 
     return Either.Right(container.object) 
    } 
} 
Смежные вопросы