我们现在可以嵌套返回协议类型的函数吗?或者情况总是如此并且文档是错误的?

问题描述 投票:0回答:2

我正在使用 SwiftUI 开发一个项目。从一开始,swiftUI 就展示了面向协议编程的强大功能和应用。所以我开始研究和扩展我对协议和不透明类型的知识。

在文档中Swift 编程语言在页面末尾明确指出:

这种方法的问题是形状变换不嵌套。翻转三角形的结果是 Shape 类型的值,并且 protoFlip(:) 函数采用符合 Shape 协议的某种类型的参数。然而,协议类型的值不符合该协议; protoFlip(:) 返回的值不符合 Shape。这意味着像 protoFlip(protoFlip(smallTriange)) 这样应用多个变换的代码是无效的,因为翻转的形状不是 protoFlip(_:) 的有效参数

但是......当我尝试嵌套该函数时,它工作得很好。那么文档是错误的还是这是语言的最新更新并且文档有点落后?

这是代码(我在操场上运行的)。

protocol Shape {
    func draw() -> String
}


struct Triangle: Shape {
    var size: Int
    
    func draw() -> String {
        var result: [String] = []
        for length in 1...size {
            result.append(String(repeating: "*", count: length))
        }
        return result.joined(separator: "\n")
    }

//return type is a protocol
func protoFlip<T: Shape>(_ shape: T) -> Shape {
    if shape is Square {
        return shape
    }
    
    return FlippedShape(shape: shape)
}


//Testing if nested function works
let smallTriangle = Triangle(size: 3)
let testNest = protoFlip(protoFlip(smallTriangle))
swift generics swiftui swift-protocols
2个回答
1
投票

我认为这本书用了一个不好的例子来说明问题。一般来说,您的代码将正确编译并运行。但是协议方法中的一些快速功能,例如关联类型自我要求,打破了我们过去习惯的多态性概念。

为了总结我所说的内容,请看一下这段代码:

protocol Shape: Equatable {
    
    func draw() -> String
    
    func doSomething(with other: Self) // self requirement
}

struct Triangle: Shape {
    var size: Int
    func draw() -> String {
        var result: [String] = []
        for length in 1...size {
            result.append(String(repeating: "*", count: length))
        }
        return result.joined(separator: "\n")
    }
    
    func doSomething(with other: Self) {
        print("Tri size: \(other.size)")
    }
}


struct FlippedShape<T: Shape>: Shape {
    var shape: T
    func draw() -> String {
        let lines = shape.draw().split(separator: "\n")
        return lines.reversed().joined(separator: "\n")
    }
    
    func doSomething(with other: Self) {
        print("Other filled shape: \(other.draw())")
    }
}

struct Rect: Shape {
    var width: Int
    var height: Int
    
    func draw() -> String {
        let line = String(repeating: "*", count: width)
        let result = Array<String>(repeating: line, count: height)
        return result.joined(separator: "\n")
    }
    
    func doSomething(with other: Self) {
        print("W: \(other.width) H:\(other.height)")
    }
}

func protoFlip<T: Shape>(_ shape: T) -> Shape { //Compiler emits error:  Use of protocol 'Shape' as a type must be written 'any Shape'

    return FlippedShape(shape: shape)
}

let smallTriangle = Triangle(size: 3)

let protoFlippedTriangle = protoFlip(protoFlip(protoFlip(smallTriangle)))
print(protoFlippedTriangle.draw())

如果没有不透明类型,此代码将无法编译,因为在这种情况下,编译器需要检查我们传递给函数的形状是否与返回的形状相同。因为我们不能在除相同类型的形状之外的任何其他形状上调用 doSomething


© www.soinside.com 2019 - 2024. All rights reserved.