这个简单的Swift函数构建器示例有什么问题?

时间:2019-11-07 07:12:38

标签: swift function-builder

我正在尝试在XCode 11中尝试使用功能构建器,并构建了这个简单的游乐场。似乎没有使用函数生成器将输入转换为所需的结果闭包,但是我觉得我必须在某处缺少要点。最后一行报告的错误为cannot convert value of type '(Int, Int)' to closure result type 'Scene'

import SpriteKit

public protocol Scene {
    var width   : Int {get}
    var height  : Int {get}
}

public struct EmptyScene : Scene {
    public let width : Int
    public let height: Int
}

@_functionBuilder public struct SceneBuilder {
    public static func buildBlock(_ size:(Int,Int))->Scene {
        return EmptyScene(width: size.0, height: size.1)
    }
}

extension SKScene {
    public convenience init(@SceneBuilder _ scene :  () -> Scene){
        let definition = scene()
        self.init(size: CGSize(width: definition.width, height: definition.height))
    }
}

SKScene {
    (320,256)
}

2 个答案:

答案 0 :(得分:1)

我认为您错过了一步。我认为函数构建器是我必须添加到函数中的注释,因此带注释的函数具有更好的调用位置(仅在大括号内包含一些值,可以帮助快速进行合成/填充)。我对SpriteKit不太了解,但编译器对此感到满意:

import PlaygroundSupport
import SpriteKit

import SpriteKit

public protocol Scene {
    var width   : Int {get}
    var height  : Int {get}
}

public struct EmptyScene : Scene {
    public let width : Int
    public let height: Int
}

@_functionBuilder public struct SceneBuilder {
    public static func buildBlock(_ size:(Int,Int))->Scene {
        return EmptyScene(width: size.0, height: size.1)
    }
}

extension SKScene {
    public convenience init(@SceneBuilder _ scene :  () -> Scene){
        let definition = scene()
        self.init(size: CGSize(width: definition.width, height: definition.height))
    }
}

*here*

@SceneBuilder
func buildDaScene() -> Scene { (320, 256) }

SKScene { buildDaScene() }

答案 1 :(得分:0)

这是一个Swift错误:函数构建器中不考虑单表达式闭包。 (请参阅here,尽管目前尚不清楚哪个Swift版本可以解决该问题。)

我添加了另一个buildBlock方法,该方法采用多个元组(并且忽略除第一个之外的所有元组),并且确实可以使用。

@_functionBuilder public struct SceneBuilder {

// no difference whether or not we keep the old buildBlock as well
    public static func buildBlock(_ size: (Int,Int)...) ->  Scene {
        return EmptyScene(width: size[0].0, height: size[0].1)
    }
}

SKScene {
    (320,256)
} // won't compile

SKScene {
    (320,256)
    (321,257)
} // creates one SKScene with (320,256)

无论如何,将单表达式闭包传递给函数恰好是您不需要需要函数生成器的用例,并且按预期工作:

extension SKScene {
    public convenience init(_ tupleClosure: () -> (Int,Int)){
        self.init(size: CGSize(width: tupleClosure().0, height: tupleClosure().1))
    }
}

SKScene {
    (320, 256)
} // creates the scene

如果要在闭包中处理所有后续表达式,则需要函数构建器,而在引入此功能之前是不可能的。

所以好消息是您已经知道如何构造它们(嗯,在11月就已经知道了:)),并且它们应该与多个表达式一起使用……并且单个表达式的解决方案已经存在(还有一种解决方法那些。)