使用协议在另一个associatedType内使用associatedType

时间:2017-05-11 20:45:44

标签: swift generics

我一直在努力寻找一个解决方案,使用泛型和相关类型在另一个相关类型中解决上述问题

案例

我想要一个ObjectRequestType,其中包含ObjectResponseType类型的关联类型。

protocol ObjectRequestType {
    associatedtype Response: ObjectResponseType
}
另一方面,

ObjectResponseType是具有关联类型Element

的协议
protocol ObjectResponseType {
    associatedtype Element
}

我想要实现的是我想根据不同类型的元素扩展ObjectRequestType的功能,这里为了示例我们有两种不同类型的Element

protocol ElementType {}
protocol OtherElementType {}

到目前为止,我将通过以下扩展程序实现此目的

extension ObjectRequestType where Response.Element: ElementType {
    static func request() {
        print("ElementType")
    }
}

extension ObjectRequestType where Response.Element: OtherElementType {
    static func request() {
        print("OtherElementType")
    }
}

额外的步骤是处理将此请求传递给我需要使用泛型的类

class DemoClass<Request: ObjectRequestType> {
    static func execute() {
        Request.request()
    }
}

问题

由于动态DemoClass无法定义Response Request有哪种OtherElementType,它会找到它的两个实现,并且它将无法抛出编译错误

  

错误:对成员'request()'

的模糊引用

通过添加额外的where子句来修改类仍然不会这样做,因为我会错过class DemoClass<Request: ObjectRequestType> where Request.Response.Element: ElementType { static func execute() { Request.request() } } 的其余实现

foreach ($Comp in (Get-Content 'C:\full_path_to_the_source_file\hosts.txt')) {
    foreach ($UserFolder in (Get-ChildItem "\\$Comp\c$\Users" -Directory)) {

        $DocumentsFolder = Join-Path ($UserFolder.FullName) 'Documents'
        $DesktopFolder = Join-Path ($UserFolder.FullName) 'Desktop'

        $DocumentsSize = (Get-ChildItem $DocumentsFolder -Recurse | Measure-Object -property length -sum -ErrorAction SilentlyContinue)
        $DesktopSize = (Get-ChildItem $DesktopFolder -Recurse | Measure-Object -property length -sum -ErrorAction SilentlyContinue)

        $DocumentOutput = "$Comp $UserFolder Documents {0:N1}" -f ($DocumentsSize.sum / 1GB) + "GB"
        $DesktopOutput = "$Comp $UserFolder Desktop {0:N1}" -f ($DesktopSize.sum / 1GB) + "GB"

        $DocumentOutput | Out-File \\Some_Server\Share\Results\Results.txt -Append
        $DesktopOutput | Out-File \\Some_Server\Share\Results\Results.txt -Append

    }
}

我一直在尝试使用它的解决方法,但我仍然无法实现这种情况。如果有人有任何想法或其他方法,我们将非常欢迎。

1 个答案:

答案 0 :(得分:2)

执行此操作的常用方法是将request方法添加到ObjectResponseType协议中,以便您可以保证它存在于任何符合标准的类型上。然后,您创建一个协议扩展,为您已知的如何处理的类型提供默认实现,您已经完成了。如果您需要使用现有元素类型之一覆盖某个请求的请求,则可以执行此操作。如果您需要支持其他元素类型,您可以在请求中执行此操作,也可以添加其他协议扩展名。

protocol ObjectResponseType {
    associatedtype Element
}
protocol ObjectRequestType {
    associatedtype Response: ObjectResponseType

    static func request()
}

protocol ElementType {}

extension ObjectRequestType where Response.Element: ElementType {
    static func request() {
        print("ElementType")
    }
}
protocol OtherElementType {}
extension ObjectRequestType where Response.Element: OtherElementType {
    static func request() {
        print("OtherElementType")
    }
}

class DemoClass<Request: ObjectRequestType> {
    static func execute() {
        Request.request()
    }
}

class Foo: ElementType {}
class FooResponse: ObjectResponseType {
    typealias Element = Foo
}
class FooRequest: ObjectRequestType {
    typealias Response = FooResponse
}

class Bar: OtherElementType {}
class BarResponse: ObjectResponseType {
    typealias Element = Bar
}
class BarRequest: ObjectRequestType {
    typealias Response = BarResponse
    // Override the default implementation
    static func request() {
        print("Bar")
    }
}

class Baz {}
class BazResponse: ObjectResponseType {
    typealias Element = Baz
}
class BazRequest: ObjectRequestType {
    typealias Response = BazResponse

    static func request() {
        print("Baz")
    }
}

DemoClass<FooRequest>.execute() // ElementType
DemoClass<BarRequest>.execute() // Bar
DemoClass<BazRequest>.execute() // Baz