Возврат объекта, который соответствует универсальному ограничению - PullRequest
0 голосов
/ 30 апреля 2019

Я пытаюсь создать Builder для моего ComplexObject:

import Foundation

class ComplexObject {
    // lots of stuff

    init<ObjectType, T>(_ closure: ((ObjectType) -> T)) {
        // lots of init/setup code
    }

    // other initializers with generics, constructed 
    // by other Builders than ConcreteBuilder<O> below
}

protocol BuilderType {
    associatedtype ObjectType
    func title(_: String) -> Self
    func build<T>(_ closure: ((ObjectType) -> T)) -> ComplexObject
}

struct Injected<O> {
    //...
}

extension ComplexObject {
    static func newBuilder<Builder: BuilderType, O>(someDependency: Injected<O>) -> Builder where Builder.ObjectType == O {
        // vvvv
        return ConcreteBuilder(someDependency: someDependency)
        // ^^^^
        // Cannot convert return expression of type 'ComplexObject.ConcreteBuilder<O>' to return type 'Builder'
    }

    struct ConcreteBuilder<O>: BuilderType {
        private let dependency: Injected<O>

        private var title: String

        init(someDependency: Injected<O>) {
            self.dependency = someDependency
        }

        func title(_ title: String) -> ConcreteBuilder<O> {
            var builder = self
            builder.title = title
            return builder
        }

        func build<T>(_ closure: ((O) -> T)) -> ComplexObject {
            return ComplexObject(closure)
        }
    }
}

но swiftc жалуется на return ConcreteBuilder(...) строку

Cannot convert return expression of type 'ComplexObject.ConcreteBuilder<O>' to return type 'Builder'

Я тоже пытался

static func newBuilder<Builder: BuilderType>(someDependency: Injected<Builder.ObjectType>) -> Builder {
    return ConcreteBuilder(someDependency: someDependency)
}

с тем же результатом. Я вижу, что могу просто выставить ConcreteBuilder, но я надеялся, что смогу скрыть детали реализации. Что мне здесь не хватает?

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

Я не уверен, как решить эту проблему, но корень проблемы в том, что newBuilder(someDependancy:) имеет сигнатуру общего типа, но на самом деле это не универсальная.

Возвращаемый тип утверждает, что функция может возвращать объект любого типа T: BuilderType where Builder.ObjectType == O, но это явно не так. Запрос этой функции на возврат любого типа, кроме ConcreteBuilder, не поддерживается. В лучшем случае вы можете использовать принудительное приведение, но если кто-то напишет let myBuilder: MyBuilder = ComplexObject.newBuilder(someDependancy: dec), код будет аварийно завершен (даже если MyBuilder удовлетворяет вашим общим ограничениям), потому что вы пытаетесь принудительно привести приведение ConcreteBuilder к MyBuilder.

Что касается решения ... У меня его нет. По сути, вы просто хотите вернуть BuilderType, но я не думаю, что это возможно, потому что у него есть связанный тип.

0 голосов
/ 30 апреля 2019

Будет ли это делать?

return ConcreteBuilder(someDependency: someDependency) as! Builder
...