如何在Swift中实现类似Java @FunctionalInterface的函数式协议?
Swift 实现类似 Java @FunctionalInterface 的语法糖
如果你想在Swift里实现类似Java @FunctionalInterface的效果,用闭包快速创建单方法协议的实例,Swift 5.9引入的宏确实是最优解,也可以用手动扩展的方式替代。下面是具体实现方案:
一、基于Swift宏的自动实现
通过自定义@functionalProtocol宏,可以自动帮你生成闭包包装结构体,省去手动编写ClosureArgumentChecker这类样板代码的麻烦。
1. 创建宏Target
首先需要在项目中添加一个宏Target(类型选Macro),然后实现宏逻辑:
import SwiftSyntax import SwiftSyntaxBuilder import SwiftSyntaxMacros public struct FunctionalProtocolMacro: PeerMacro { public static func expansion( of node: AttributeSyntax, providingPeersOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { // 确保只作用于协议 guard let protocolDecl = declaration.as(ProtocolDeclSyntax.self) else { fatalError("@functionalProtocol 仅支持协议类型") } // 过滤协议中的方法,只处理单方法协议 let methodDecls = protocolDecl.memberBlock.members.compactMap { $0.decl.as(FunctionDeclSyntax.self) } guard methodDecls.count == 1, let targetMethod = methodDecls.first else { fatalError("@functionalProtocol 仅支持只包含单个方法的协议") } // 生成包装结构体名称 let wrapperStructName = "Closure\(protocolDecl.name.text)" let methodParams = targetMethod.signature.parameterClause.parameters let methodReturnType = targetMethod.signature.returnType?.type.description ?? "Void" // 生成闭包包装结构体 let wrapperStruct = try StructDeclSyntax( structKeyword: .structKeyword, name: IdentifierSyntax(wrapperStructName), inheritanceClause: InheritanceClauseSyntax { InheritanceClauseElementSyntax(type: TypeSyntax(stringLiteral: protocolDecl.name.text)) }, memberBlock: MemberBlockSyntax { // 定义闭包属性 try VariableDeclSyntax( bindingKeyword: .keyword(.let), bindings: [ PatternBindingSyntax( pattern: IdentifierPatternSyntax(identifier: "closure"), typeAnnotation: TypeAnnotationSyntax( type: FunctionTypeSyntax { for param in methodParams { FunctionTypeParameterSyntax(type: param.type) } FunctionTypeArrowSyntax(), TypeSyntax(stringLiteral: methodReturnType) } ) ) ] ) // 实现协议方法,内部调用闭包 try FunctionDeclSyntax( funcKeyword: .funcKeyword, name: targetMethod.name, signature: targetMethod.signature, body: FunctionBodySyntax { CodeBlockItemSyntax( item: ExprSyntax( FunctionCallExprSyntax( calledExpression: IdentifierExprSyntax(identifier: "closure"), leftParen: .leftParenToken(), arguments: LabeledExprListSyntax { for param in methodParams { LabeledExprSyntax( label: param.firstName, expression: IdentifierExprSyntax(identifier: param.firstName.text) ) } }, rightParen: .rightParenToken() ) ) ) } ) } ) // 生成协议扩展,添加闭包转协议的静态方法 let protocolExtension = try ExtensionDeclSyntax( extensionKeyword: .extensionKeyword, extendedType: TypeSyntax(stringLiteral: protocolDecl.name.text) ) { try FunctionDeclSyntax( funcKeyword: .funcKeyword, modifiers: [DeclModifierSyntax(name: .keyword(.static))], name: IdentifierSyntax("from"), signature: FunctionSignatureSyntax( parameterClause: ParameterClauseSyntax { FunctionParameterSyntax( firstName: .identifier("_"), type: FunctionTypeSyntax { for param in methodParams { FunctionTypeParameterSyntax(type: param.type) } FunctionTypeArrowSyntax(), TypeSyntax(stringLiteral: methodReturnType) } ) }, returnType: ReturnTypeSyntax(type: TypeSyntax(stringLiteral: protocolDecl.name.text)) ), body: FunctionBodySyntax { CodeBlockItemSyntax( item: ExprSyntax( FunctionCallExprSyntax( calledExpression: IdentifierExprSyntax(identifier: wrapperStructName), leftParen: .leftParenToken(), arguments: LabeledExprListSyntax { LabeledExprSyntax( label: .identifier("closure"), expression: IdentifierExprSyntax(identifier: "_") ) }, rightParen: .rightParenToken() ) ) } ) } } return [wrapperStruct, protocolExtension] } } // 注册宏 public enum FunctionalMacros: Macro { public static var provideMacros: [String: Macro.Type] { ["functionalProtocol": FunctionalProtocolMacro.self] } }
2. 在主代码中使用宏
在主Target中导入宏模块,然后按如下方式使用:
import Foundation import FunctionalMacros @functionalProtocol protocol ArgumentChecker { func check(args: [String]) -> Bool } // 直接用闭包生成协议实例 let checker: ArgumentChecker = ArgumentChecker.from { args in args.isEmpty } func main() { guard checker is ArgumentChecker else { print("checker is not an ArgumentChecker") return } print("checker is an ArgumentChecker") let args = ["Hello", "World"] let result = checker.check(args: args) print("Result: \(result)") } main()
二、无宏替代方案(手动扩展)
如果不想引入宏,也可以为每个单方法协议手动添加扩展,实现类似效果:
protocol ArgumentChecker { func check(args: [String]) -> Bool } extension ArgumentChecker { static func from(_ closure: ([String]) -> Bool) -> Self { // 内部定义包装结构体 struct ClosureChecker: ArgumentChecker { let closure: ([String]) -> Bool func check(args: [String]) -> Bool { closure(args) } } return ClosureChecker(closure: closure) as! Self } } // 使用方式和宏方案一致 let checker = ArgumentChecker.from { $0.isEmpty }
这种方式无需依赖宏,但需要为每个符合要求的协议手动编写扩展,适合不想引入宏模块的场景。
内容的提问来源于stack exchange,提问作者code_by_cr
相关产品推荐
相关产品推荐

