如何在 Swift 宏中应用自定义协议?

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

我在学习 Swift Macros 时有一个问题。

当特定类型想要遵守 Swift 宏中的自定义协议时,是否应该在宏包中声明该自定义协议?或者可以在主应用程序项目中声明吗?

例如,如果@ServiceProvidable宏使特定类符合ServiceProvidable协议,并用计算属性扩展代码,那么应该如何实现?

@ServiceProvidable
class ViewControllerWrapper {

}

// Expanding a macro
class ViewControllerWrapper { } 
extension ViewControllerWrapper: ServiceProvidable {
    var service: ServiceProviderProtocol {
        guard 
            let serviceProvider = (UIApplication.shared.delegate as? AppDelegate)?.serviceProvider
        else { return ServiceProvider() }
        return serviceProvider
    }
}
swift macros protocols
1个回答
0
投票

在声明宏时,您需要指定宏提供的一致性。例如

@attached(extension, conformances: FooProtocol) // You need to be able to say "FooProtocol" here
public macro MyMacro() = #externalMacro(module: "SomeImplementationModule", type: "MyMacro")

因此,协议应该在上面的代码可以访问的模块中声明,因此要么在与上面的代码相同的模块中,要么在其依赖项之一中。我通常只是把它放在宏声明旁边。

@attached(extension, conformances: FooProtocol) // You need to be able to say "FooProtocol" here
public macro MyMacro() = #externalMacro(module: "SomeImplementationModule", type: "MyMacro")

public protocol FooProtocol {
    func foo()
}

请注意,这是不是实现宏的模块。

您应该在另一个模块中实现该宏(在上面的示例中,在名为“SomeImplementationModule”的模块中),该模块是在 Package.swift 中使用

.macro(...)
而不是
.target(...)
创建的。

这是一个示例实现:

enum MyMacro: ExtensionMacro {
    static func expansion(
        of node: AttributeSyntax,
        attachedTo declaration: some DeclGroupSyntax,
        providingExtensionsOf type: some TypeSyntaxProtocol,
        conformingTo protocols: [TypeSyntax],
        in context: some MacroExpansionContext
    ) throws -> [ExtensionDeclSyntax] {
        let name = declaration.as(ClassDeclSyntax.self)!.name
        return [
            try ExtensionDeclSyntax("extension \(name): FooProtocol") {
                """
                public func foo() { print("example implementation") }
                """
            }
        ]
    }
}


@main
struct MyMacroPlugin: CompilerPlugin {
    let providingMacros: [Macro.Type] = [
        MyMacro.self
    ]
}
© www.soinside.com 2019 - 2024. All rights reserved.