You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:02:15