美文网首页
WWDC2023-编写 Swift 宏

WWDC2023-编写 Swift 宏

作者: 哈啰于先生 | 来源:发表于2023-06-07 12:09 被阅读0次

    探索如何使用 Swift 宏来使您的代码库更具表现力和更易于阅读。在我们探索宏如何帮助您避免编写重复代码并了解如何在您的应用程序中使用它们时,请继续编写代码。我们将分享宏的构建块,向您展示如何对其进行测试,并指导您了解如何从宏中发出编译错误。

    1、stringify 宏的声明

    @freestanding(expression)
    public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "WWDCMacros", type: "StringifyMacro")
    

    这段代码是一个使用 Swift 的宏定义的例子。代码中定义了一个名为 stringify 的宏函数,该函数接受一个参数 value,并返回一个元组 (T, String)。宏函数使用了 #externalMacro 指令来引用外部模块中的宏定义。
    宏函数的作用是将传入的值转换为字符串形式,并返回原始值和对应的字符串。宏函数的具体实现在名为 "StringifyMacro" 的外部模块中,该模块的实现可以在代码中其他地方进行定义和导入。
    此代码片段中的 @freestanding(expression)注解表示该宏定义是在无依赖环境中运行的,即不依赖于任何其他代码或库。

    在上面的注解中,@freestanding(expression) 表示这个宏函数是一个自由函数(freestanding function)宏,它可以在任何上下文中使用,而不仅仅局限于特定的语法结构或类型。
    在这个特定的宏函数中,expression是一个泛型参数,用于接受传入的表达式作为参数。在宏函数的实现中,可以使用这个表达式进行进一步的处理和展开。
    例如,在 StringifyMacroexpansion 方法中,通过 node.argumentList.first?.expression 获取传入的表达式作为参数,并对该表达式进行处理和展开。这个表达式可以是任何合法的表达式,根据具体的使用情况来确定。
    总结来说,expression 在这个上下文中表示宏函数接受的表达式参数。

    2、stringify 宏的实现

    public struct StringifyMacro: ExpressionMacro {
        public static func expansion(
            of node: some FreestandingMacroExpansionSyntax,
            in context: some MacroExpansionContext
        ) -> ExprSyntax {
            guard let argument = node.argumentList.first?.expression else {
                fatalError("compiler bug: the macro does not have any arguments")
            }
    
            return "(\(argument), \(literal: argument.description))"
        }
    }
    

    上述代码是一个 Swift 宏函数的示例实现,用于实现字符串化操作。
    这段代码定义了一个名为 StringifyMacro 的结构体,它采用了 ExpressionMacro 协议。ExpressionMacro 是用于表达式级宏函数的协议,它规定了宏函数需要实现的方法。
    StringifyMacro 结构体中的 expansion 方法是宏函数的具体实现。该方法接受两个参数:nodecontext,分别表示宏函数的展开节点和展开上下文。
    expansion 方法中,首先通过 node.argumentList.first?.expression 来获取宏函数的第一个参数表达式。如果参数不存在,则抛出一个错误。
    然后,通过字符串插值的方式构建一个新的表达式语法树,该表达式由原始参数表达式和该参数表达式的描述字符串组成。这里使用了 literal 辅助函数来将字符串转化为表达式。
    最后,将构建的表达式返回作为宏函数的展开结果。
    总的来说,上述代码实现了一个简单的宏函数,它将传入的参数表达式转化为一个包含原始参数和参数描述的元组表达式。这样,使用该宏函数时,可以方便地获取参数的值和描述信息。

    3、调用 stringify 宏

    import WWDC
    
    let a = 17
    let b = 25
    
    let (result, code) = #stringify(a + b)
    
    print("The value \(result) was produced by the code \"\(code)\"")
    

    上述代码使用了名为 #stringify 的宏函数来将表达式 a + b转化为字符串。
    首先,通过 import WWDC 导入了一个名为 WWDC 的模块,该模块可能包含了宏函数的实现。
    然后,定义了两个整数变量 ab,分别赋值为 1725
    接下来,使用 #stringify 宏函数对表达式 a + b 进行字符串化操作,将其转化为一个元组 (result, code)
    最后,通过 print 函数打印出字符串,其中包含了转化后的结果和代码。
    运行该代码,将输出以下内容:

    The value 42 was produced by the code "a + b"
    

    这说明宏函数将表达式 a + b 转化为了字符串 "a + b",并将计算结果 42 赋值给了 result

    4、stringify 宏测试

    final class WWDCTests: XCTestCase {
        func testMacro() {
            assertMacroExpansion(
                """
                #stringify(a + b)
                """,
                expandedSource: """
                (a + b, "a + b")
                """,
                macros: testMacros
            )
        }
    }
    
    let testMacros: [String: Macro.Type] = [
        "stringify": StringifyMacro.self
    ]
    

    上述代码是一个针对宏函数 #stringify 的单元测试。
    首先,定义了一个名为 WWDCTestsXCTestCase 子类。在该类中,声明了一个名为 testMacro 的测试方法。
    testMacro 方法中,调用了 assertMacroExpansion 函数,用于断言宏函数的扩展结果是否符合预期。
    assertMacroExpansion 函数接受三个参数:
    input:要扩展的源代码字符串。
    expandedSource:期望的宏扩展后的源代码字符串。
    macros:包含了宏函数名称和对应的宏类型的字典。在测试代码中,使用 #stringify(a + b) 作为输入,表示要对表达式 a + b 进行字符串化操作。预期的宏扩展结果是 (a + b, "a + b"),即将表达式本身 (a + b)和它的字符串表示形式 "a + b" 组成一个元组。
    最后,通过定义了一个名为testMacros的字典,将宏函数名称 "stringify" 和对应的宏类型 StringifyMacro.self关联起来。
    这样,测试代码就准备好了,可以通过运行测试来验证宏函数的扩展结果是否与预期一致。

    相关文章

      网友评论

          本文标题:WWDC2023-编写 Swift 宏

          本文链接:https://www.haomeiwen.com/subject/ahinedtx.html