{"data":{"post":{"title":"再探 Swift 宏 - 陷阱与缺陷","subtitle":"","isPublished":true,"createdTime":"2023-08-10T00:00:00.000Z","lastModifiedTime":null,"license":null,"tags":["Swift","宏"],"category":"编程","file":{"childMdx":{"excerpt":"在之前的文章中，我们学习了使得 Swift 宏独一无二的优势和本质。文中的示例工作正常，但是我们现在可以放心大胆地实现任何 Swift 宏了吗？ 答案是否定的。 给 Swift…","code":{"body":"function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nconst layoutProps = {};\nreturn class MDXContent extends React.Component {\n  constructor(props) {\n    super(props);\n    this.layout = null;\n  }\n\n  render() {\n    const _this$props = this.props,\n          {\n      components\n    } = _this$props,\n          props = _objectWithoutProperties(_this$props, [\"components\"]);\n\n    return React.createElement(MDXTag, {\n      name: \"wrapper\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在之前的文章中，我们学习了使得 Swift 宏独一无二的优势和本质。文中的示例工作正常，但是我们现在可以放心大胆地实现任何 Swift 宏了吗？`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `答案是否定的。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `给 Swift 宏带来优势的特性也会引入陷阱与缺陷，从而让程序员自己给自己造成麻烦。在本文中，我想向你展示我发现的一些问题以及避免它们的方法。`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `陷阱与缺陷`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `控制流的潜在混乱`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在之前的文章中的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 示例中，Swift 宏展开可能涉及到`, React.createElement(MDXTag, {\n      name: \"strong\",\n      components: components,\n      parentName: \"p\"\n    }, `控制流操控`), `和`, React.createElement(MDXTag, {\n      name: \"strong\",\n      components: components,\n      parentName: \"p\"\n    }, `词法作用域共享`), `：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之前：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  #unwrap(bar) {\n    print(bar)\n  }\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之后：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // #unwrap 宏展开开始\n  guard let bar = bar else {\n    return\n  }\n  print(bar)\n  // #unwrap 宏展开结束\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `由于示例宏展开中涉及控制流的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `return`), ` 语句是有意行为，所以这并不让人感到意外。但是如果我们将这个宏放在循环中呢？请看下面这个例子：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之前：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  for _ in 0..<10 {\n    #unwrap(bar) {\n      print(bar)\n    }\n  }\n  // 其余代码\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之后：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  for _ in 0..<10 {\n    // #unwrap 宏展开开始\n    guard let bar = bar else {\n      return\n    }\n    print(bar)\n    // #unwrap 宏展开结束\n  }\n  // 其余代码\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `通过上面的宏展开，我们可以知道如果将空值传递给 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `foo`), `，则 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `for`), ` 循环后的其余代码不会被执行。这是因为宏展开引入的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `return`), ` 语句会中断外部循环。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 宏的名称只传达了对可选值解包的目的。这可能会让使用这个宏的程序员认为从应用点返回是一个`, React.createElement(MDXTag, {\n      name: \"strong\",\n      components: components,\n      parentName: \"p\"\n    }, `意外行为`), `。`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `Freestanding Macro 中的命名冲突`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `以上提到的意外并不是我给出的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 宏展开中唯一存在的潜在陷阱。这里还有一个陷阱：在宏展开的过程中可能会引起变量重复声明。让我们继续检查该宏的展开:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // #unwrap 宏展开开始\n  guard let bar = bar else {\n    return\n  }\n  print(bar)\n  // #unwrap 宏展开结束\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这个宏展开引入了变量名 shadowing，其中 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `guard let bar: Int`), ` shadow 了参数 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_ bar: Int?`), `。对于 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 来说，变量名 shadowing 是无足轻重的，因为这是一种有意的行为。然而，由于 freestanding Swift macro 的宏展开涉及应用点的词法作用域共享，这使得一些朴素实现的宏展开可能会使得变量名 shadowing 变成变量名重复声明。以下是一个人造的例子：由于宏展开，变量名 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `updater`), ` 从被 shadow 变成被重复声明。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之前:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  let updater = Updater()\n  #unwrap(bar) {\n    let updater = Updater()\n    print(bar)\n    updater.update()\n  }\n  print(updater.description)\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之后:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // \\`updater\\` 第一次被声明\n  let updater = Updater()\n  // #unwrap 宏展开开始\n  guard let bar else {\n    return\n  }\n  // \\`updater\\` 第二次被声明\n  let updater = Updater()\n  print(bar)\n  updater.update()\n  // #unwrap 宏展开结束\n  print(updater.description)\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在 Xcode 中进行一次 clean build，你会发现这个例子无法编译:`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/08d94/compilation-failure-variable-redeclaration-expanding-unwrap.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/0cc25/compilation-failure-variable-redeclaration-expanding-unwrap.png\",\n        \"srcSet\": [\"/static/4f67b11a38fb483fa19b34ea24fdb1fa/5116e/compilation-failure-variable-redeclaration-expanding-unwrap.png 178w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/92f55/compilation-failure-variable-redeclaration-expanding-unwrap.png 356w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/0cc25/compilation-failure-variable-redeclaration-expanding-unwrap.png 712w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/7ae06/compilation-failure-variable-redeclaration-expanding-unwrap.png 1068w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/eee47/compilation-failure-variable-redeclaration-expanding-unwrap.png 1424w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/38407/compilation-failure-variable-redeclaration-expanding-unwrap.png 2136w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/240a0/compilation-failure-variable-redeclaration-expanding-unwrap.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/690c8/compilation-failure-variable-redeclaration-expanding-unwrap.webp\",\n        \"srcSet\": [\"/static/4f67b11a38fb483fa19b34ea24fdb1fa/25c8a/compilation-failure-variable-redeclaration-expanding-unwrap.webp 178w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/60698/compilation-failure-variable-redeclaration-expanding-unwrap.webp 356w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/690c8/compilation-failure-variable-redeclaration-expanding-unwrap.webp 712w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/d7e52/compilation-failure-variable-redeclaration-expanding-unwrap.webp 1068w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/456ef/compilation-failure-variable-redeclaration-expanding-unwrap.webp 1424w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/2a654/compilation-failure-variable-redeclaration-expanding-unwrap.webp 2136w\", \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/08d94/compilation-failure-variable-redeclaration-expanding-unwrap.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4f67b11a38fb483fa19b34ea24fdb1fa/08d94/compilation-failure-variable-redeclaration-expanding-unwrap.webp\",\n        \"alt\": \"#unwrap 宏展开导致的变量重复声明从而引起的编译错误\",\n        \"title\": \"#unwrap 宏展开导致的变量重复声明从而引起的编译错误\",\n        \"width\": 712,\n        \"height\": 477,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            #unwrap 宏展开导致的变量重复声明从而引起的编译错误\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `Attached Macro 中的命名冲突`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `潜在的命名冲突不仅可以在 freestanding macro 中产生，还可以在 attached macro 中产生。我们可以从之前那篇文章中的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏示例中了解到这一点。让我们回顾一下这个示例的宏展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n\n  // @COW 宏展开开始\n  private class Storage {\n\n    var name: String\n\n    // 其他属性 ...\n\n  }\n\n  private var _$storage: Storage\n\n  private func makeStorageUniqueIfNeeded() {\n    if !isKnownUniquelyReferenced(&_$storage) {\n      _$storage = Storage(name: name, ...)\n    }\n  }\n\n  init(name: String, ...) {\n    self._storage = Storage(name: name, ...)\n  }\n  // @COW 宏展开结束\n\n  // @COW 宏展开开始\n  @COWIncluded(storage: _$storage)\n  // @COW 宏展开结束\n  var name: String {\n    // @COWIncluded 宏展开开始\n    get { return _$storage.name }\n    set {\n      makeStorageUniqueIfNeeded()\n      _$storage.name = newValue\n    }\n    // @COWIncluded 宏展开结束\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `你可能已经注意到，在宏展开中新增的一个成员带有 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_$`), ` 前缀这个命名模式。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `  private var _$storage: Storage\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这是我从苹果的 Swift Observation 和 SwiftData 宏实现中学到的命名习惯，该习惯可以保护宏展开的实现细节不被程序员意外访问。然而，这并不能保护这些成员免受其他宏带来的意外重声明或访问 —— 因为程序员可能也应用了其他宏，而这些宏可能会添加重复名称的成员或者误用其他宏添加的成员。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `例如，假设有一个叫做 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 的宏，它通过添加一对 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `subscript`), ` getter 和 setter 使被应用的类型表现得像一个字典。然后我们在 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏示例中使用的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `User`), ` 结构体上应用 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 宏：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@DictionaryLike\nstruct User {\n\n  // 其他内容 ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 可以被展开为以下代码：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@DictionaryLike\nstruct User {\n\n  // 其他内容 ...\n\n  // @DictionaryLike 宏展开开始\n  var _$storage: [String : Any] = [:]\n\n  subscript(_ key: String) -> Any? {\n    get { return _$storage[key] }\n    set { _$storage[key] = newValue }\n  }\n  // @DictionaryLike 宏展开结束\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `一旦我们将 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 叠加到同一类型上，就会出现这样的情况：即 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 都向被应用的类型添加了一个名为 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_$storage`), ` 的成员。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\n@DictionaryLike\nstruct User {\n\n  // 其他内容 ...\n\n  // 由 @COW 宏展开引入\n  var _$storage: Storage\n\n  // 由 @DictionaryLike 宏展开引入\n  var _$storage: [String : Any] = [:]\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `显然，这在 Swift 中无法编译，因为 Swift 不允许属性重载。在这种情况下，我们会再次得到 \"invalid redeclaration of a variable\" 错误。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/4d9bf7fd02b4bcede954432a5c24571c/08d94/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4d9bf7fd02b4bcede954432a5c24571c/0cc25/compilation-failure-variable-redeclaration-expanding-dictionary-like.png\",\n        \"srcSet\": [\"/static/4d9bf7fd02b4bcede954432a5c24571c/5116e/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 178w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/92f55/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 356w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/0cc25/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 712w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/7ae06/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 1068w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/eee47/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 1424w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/38407/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 2136w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/240a0/compilation-failure-variable-redeclaration-expanding-dictionary-like.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4d9bf7fd02b4bcede954432a5c24571c/690c8/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp\",\n        \"srcSet\": [\"/static/4d9bf7fd02b4bcede954432a5c24571c/25c8a/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 178w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/60698/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 356w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/690c8/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 712w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/d7e52/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 1068w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/456ef/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 1424w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/2a654/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 2136w\", \"/static/4d9bf7fd02b4bcede954432a5c24571c/08d94/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/4d9bf7fd02b4bcede954432a5c24571c/08d94/compilation-failure-variable-redeclaration-expanding-dictionary-like.webp\",\n        \"alt\": \"由于 @DictionaryLike 宏展开而导致的变量重复声明从而引发的编译失败\",\n        \"title\": \"由于 @DictionaryLike 宏展开而导致的变量重复声明从而引发的编译失败\",\n        \"width\": 712,\n        \"height\": 477,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            由于 @DictionaryLike 宏展开而导致的变量重复声明从而引发的编译失败\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `唯一语言结构的命名冲突`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在 Swift 中，一些语言结构在其父一级结构下是唯一的。这意味着当多个宏尝试在相同的父一级结构中生成相同的子结构时，代码会变得无法编译。例如，属性声明中的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor —— 如果我们在属性声明中添加多个 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` accessor，那么代码将无法编译。这个错误一般很少在手写代码中发生，但在使用宏时需要引起注意。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `我们可以从之前的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 示例开始深入了解这个问题。假设有一个 accessor macro 叫做 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@UseDictionaryStorage`), `，它为所附着的属性生成 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor。getter 和 setter 将访问转发到由 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 宏展开带来的存储容器中。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `宏展开之前：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\n@DictionaryLike\nstruct User {\n  \n  @UseDictionaryStorage\n  var info: [String : Any]?\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `宏展开之后：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\n@DictionaryLike\nstruct User {\n  \n  @UseDictionaryStorage\n  var info: [String : Any]? {\n    // @UseDictionaryStorage 宏展开开始\n    get {\n      return _$storage[\"info\"] as? [String : Any]?\n    }\n    set {\n      _$storage[\"info\"] = newValue\n    }\n    // @UseDictionaryStorage 宏展开结束\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，这过度简化了所发生的事情。`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏的真实展开结果是：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\n@DictionaryLike\nstruct User {\n  \n  @UseDictionaryStorage\n  @COWIncluded\n  var info: [String : Any]? {\n    // @COWIncluded 宏展开开始\n    get {\n      _$storage.info\n    }\n    set {\n      makeStorageUniqueIfNeeded()\n      _$storage.info = newValue\n    }\n    // @COWIncluded 宏展开结束\n    // @UseDictionaryStorage 宏展开开始\n    get {\n      return _$storage[\"info\"] as? [String : Any]?\n    }\n    set {\n      _$storage[\"info\"] = newValue\n    }\n    // @UseDictionaryStorage 宏展开结束\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `我们可以观察到，在 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `info`), ` 属性下生成了两个 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor。由于 Swift 的语法只允许一个属性中有一个 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), `/`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor，这个展开会导致 Swift 中的语法错误，最终使得代码无法编译。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，这还是没有看到全貌。通过应用生产级实现的 COW 宏，我们可以看到 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor 被优化为了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_read`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_modify`), ` 以生产环境中提供更好的性能，同时我们还可以观察到 Swift 不仅禁止程序员定义名称相同的多个 accessor 而且还禁止定义多个语义相同的 accessor。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/686809cc655d105e165ef129686d4370/08d94/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/686809cc655d105e165ef129686d4370/0cc25/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png\",\n        \"srcSet\": [\"/static/686809cc655d105e165ef129686d4370/5116e/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 178w\", \"/static/686809cc655d105e165ef129686d4370/92f55/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 356w\", \"/static/686809cc655d105e165ef129686d4370/0cc25/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 712w\", \"/static/686809cc655d105e165ef129686d4370/7ae06/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 1068w\", \"/static/686809cc655d105e165ef129686d4370/eee47/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 1424w\", \"/static/686809cc655d105e165ef129686d4370/38407/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 2136w\", \"/static/686809cc655d105e165ef129686d4370/240a0/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/686809cc655d105e165ef129686d4370/690c8/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp\",\n        \"srcSet\": [\"/static/686809cc655d105e165ef129686d4370/25c8a/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 178w\", \"/static/686809cc655d105e165ef129686d4370/60698/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 356w\", \"/static/686809cc655d105e165ef129686d4370/690c8/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 712w\", \"/static/686809cc655d105e165ef129686d4370/d7e52/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 1068w\", \"/static/686809cc655d105e165ef129686d4370/456ef/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 1424w\", \"/static/686809cc655d105e165ef129686d4370/2a654/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 2136w\", \"/static/686809cc655d105e165ef129686d4370/08d94/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/686809cc655d105e165ef129686d4370/08d94/compilation-failure-duplicate-accessor-expanding-use-dictionary-storage.webp\",\n        \"alt\": \"通过 @UseDictionaryStorage 宏展开产生的多重 accessor 从而引起的编译错误\",\n        \"title\": \"通过 @UseDictionaryStorage 宏展开产生的多重 accessor 从而引起的编译错误\",\n        \"width\": 712,\n        \"height\": 561,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            通过 @UseDictionaryStorage 宏展开产生的多重 accessor 从而引起的编译错误\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `引用其他框架的声明时的命名冲突`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `上面我们已经学习了几种因为添加声明而导致的潜在命名冲突的案例，你可能会认为这个列表已经完结了。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `但是不是这样的。命名冲突不仅可以由变量和属性的 accessor 等声明引起，还可以由对其他框架中声明的引用引起。我想向你展示一下如何通过重构 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏示例从而陷入这种窘境。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `上面展示的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏示例是一种朴素的实现 —— `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `makeStorageUniqueIfNeeded`), ` 函数其实是多余的，我们可以通过将其提取到一个名为 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 的类型中来消除。`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 可以包含在拥有 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏的库中。为了简化在宏展开中使用此类型的方式，我们还可以将其变成 property wrapper。下面是示例代码:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@propertyWrapper\npublic struct Box<Contents> {\n  \n  private class Heap {\n    \n    var contents: Contents\n    \n    init(contents: Contents) { self.contents = contents }\n    \n  }\n  \n  private var heap: Heap\n  \n  public init(wrappedValue: Contents) {\n    heap = Heap(contents: wrappedValue)\n  }\n  \n  public var wrappedValue: Contents {\n    get { heap.contents }\n    set {\n      makeUniqueHeapIfNeeded()\n      heap.contents = newValue\n    }\n  }\n  \n  private mutating func makeUniqueHeapIfNeeded() {\n    guard !isKnownUniquelyReferenced(&heap) else { return }\n    heap = Heap(contents: heap.contents)\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然后，我们可以通过将 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Box`), ` 附着到由宏展开引入的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_$storage`), ` 属性，从而消除原地生成的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `makeStorageUniqueIfNeeded`), ` 函数。这减少了冗余并增加了编译速度。现在这个宏的实现更加成熟了。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n\n  // @COW 宏展开开始\n  private struct Storage {\n\n    var name: String\n\n    // 其他属性 ...\n\n  }\n\n  @Box\n  private var _$storage: Storage\n\n  init(name: String, ...) {\n    self._$storage = Storage(name: name, ...)\n  }\n  // @COW 宏展开结束\n\n  // @COW 宏展开开始\n  @COWIncluded(storage: _$storage)\n  // @COW 宏展开结束\n  var name: String {\n    // @COWIncluded 宏展开开始\n    get { return _$storage.name }\n    set { _$storage.name = newValue }\n    // @COWIncluded 宏展开结束\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，类型名称 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 可能存在歧义 —— 可能还有其他框架也有一个名为 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 的类型。这种歧义也可能导致代码无法编译。下面的截图展示了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `COW`), ` 宏的生产级实现是如何解决这个问题的：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/d5527b4791abb33a86e4a8185a3e99a9/08d94/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/d5527b4791abb33a86e4a8185a3e99a9/0cc25/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png\",\n        \"srcSet\": [\"/static/d5527b4791abb33a86e4a8185a3e99a9/5116e/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 178w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/92f55/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 356w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/0cc25/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 712w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/7ae06/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 1068w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/eee47/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 1424w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/38407/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 2136w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/240a0/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/d5527b4791abb33a86e4a8185a3e99a9/690c8/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp\",\n        \"srcSet\": [\"/static/d5527b4791abb33a86e4a8185a3e99a9/25c8a/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 178w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/60698/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 356w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/690c8/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 712w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/d7e52/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 1068w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/456ef/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 1424w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/2a654/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 2136w\", \"/static/d5527b4791abb33a86e4a8185a3e99a9/08d94/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/d5527b4791abb33a86e4a8185a3e99a9/08d94/prod-level-cow-macro-resolves-non-fully-qualified-name-conflicts.webp\",\n        \"alt\": \"生产级的 @COW 宏解决潜在的名称冲突\",\n        \"title\": \"生产级的 @COW 宏解决潜在的名称冲突\",\n        \"width\": 712,\n        \"height\": 497,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            生产级的 @COW 宏解决潜在的名称冲突\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `语义冲突`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在与 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏产生 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor 竞争的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 宏示例中，我们已经了解到 accessor macro 可能会相互影响。然而，这不是 accessor macro 所带来的唯一潜在问题：一些语言特性也可能会受到 accessor macro 的干扰。看下面的例子：一个 property wrapper 附着到一个应用了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏的结构体中的存储属性上，导致代码无法编译通过。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之前的代码：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@propertyWrapper\nstruct Capitalized {\n  \n  var wrappedValue: String {\n    didSet {\n      wrappedValue = wrappedValue.capitalized\n    }\n  }\n  \n}\n\n@COW\nstruct User {\n  \n  @Capitalized\n  var name: String = \"\"\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `展开之后的代码：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n  \n  @COWIncluded\n  @Capitalized\n  var name: String = \"\" {\n    get {\n      return _$storage.name\n    }\n    set {\n      makeStorageUniqueIfNeeded()\n      _$storage.name = newValue\n    }\n  }\n\n  // ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `我们得到这个展开结果是因为 property wrapper 的「展开」发生在宏展开之后。根据这个结果，`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Capitalized`), ` property wrapper 仍然附着在 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `name`), ` 变量上，但由于宏展开，变量从存储属性变成了计算属性。最终，我们会得到编译器诊断出来的错误：`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `Property wrapper cannot be applied to a computed property`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/173a6a12fa03aef8eef9edefb759640c/08d94/compilation-failure-property-wrapper-applied-to-computed-property.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/173a6a12fa03aef8eef9edefb759640c/0cc25/compilation-failure-property-wrapper-applied-to-computed-property.png\",\n        \"srcSet\": [\"/static/173a6a12fa03aef8eef9edefb759640c/5116e/compilation-failure-property-wrapper-applied-to-computed-property.png 178w\", \"/static/173a6a12fa03aef8eef9edefb759640c/92f55/compilation-failure-property-wrapper-applied-to-computed-property.png 356w\", \"/static/173a6a12fa03aef8eef9edefb759640c/0cc25/compilation-failure-property-wrapper-applied-to-computed-property.png 712w\", \"/static/173a6a12fa03aef8eef9edefb759640c/7ae06/compilation-failure-property-wrapper-applied-to-computed-property.png 1068w\", \"/static/173a6a12fa03aef8eef9edefb759640c/eee47/compilation-failure-property-wrapper-applied-to-computed-property.png 1424w\", \"/static/173a6a12fa03aef8eef9edefb759640c/38407/compilation-failure-property-wrapper-applied-to-computed-property.png 2136w\", \"/static/173a6a12fa03aef8eef9edefb759640c/240a0/compilation-failure-property-wrapper-applied-to-computed-property.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/173a6a12fa03aef8eef9edefb759640c/690c8/compilation-failure-property-wrapper-applied-to-computed-property.webp\",\n        \"srcSet\": [\"/static/173a6a12fa03aef8eef9edefb759640c/25c8a/compilation-failure-property-wrapper-applied-to-computed-property.webp 178w\", \"/static/173a6a12fa03aef8eef9edefb759640c/60698/compilation-failure-property-wrapper-applied-to-computed-property.webp 356w\", \"/static/173a6a12fa03aef8eef9edefb759640c/690c8/compilation-failure-property-wrapper-applied-to-computed-property.webp 712w\", \"/static/173a6a12fa03aef8eef9edefb759640c/d7e52/compilation-failure-property-wrapper-applied-to-computed-property.webp 1068w\", \"/static/173a6a12fa03aef8eef9edefb759640c/456ef/compilation-failure-property-wrapper-applied-to-computed-property.webp 1424w\", \"/static/173a6a12fa03aef8eef9edefb759640c/2a654/compilation-failure-property-wrapper-applied-to-computed-property.webp 2136w\", \"/static/173a6a12fa03aef8eef9edefb759640c/08d94/compilation-failure-property-wrapper-applied-to-computed-property.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/173a6a12fa03aef8eef9edefb759640c/08d94/compilation-failure-property-wrapper-applied-to-computed-property.webp\",\n        \"alt\": \"Property wrapper cannot be applied to a computed property\",\n        \"title\": \"Property wrapper cannot be applied to a computed property.\",\n        \"width\": 712,\n        \"height\": 397,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            Property wrapper cannot be applied to a computed property.\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这不仅限于 property wrappers，`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `lazy`), ` 关键字也可能导致进入同样的死胡同。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nclass User {\n  \n  lazy var name: String = { \"Jane Doe\" }()\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nclass User {\n  \n  @COWIncluded\n  lazy var name: String = { \"Jane Doe\" }() {\n    get {\n      return _$storage.name\n    }\n    set {\n      makeStorageUniqueIfNeeded()\n      _$storage.name = newValue\n    }\n  }\n\n  // ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/a8215793ed0c3d4bee40a43cac146b85/08d94/compilation-failure-lazy-applied-to-computed-property.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/a8215793ed0c3d4bee40a43cac146b85/0cc25/compilation-failure-lazy-applied-to-computed-property.png\",\n        \"srcSet\": [\"/static/a8215793ed0c3d4bee40a43cac146b85/5116e/compilation-failure-lazy-applied-to-computed-property.png 178w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/92f55/compilation-failure-lazy-applied-to-computed-property.png 356w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/0cc25/compilation-failure-lazy-applied-to-computed-property.png 712w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/7ae06/compilation-failure-lazy-applied-to-computed-property.png 1068w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/eee47/compilation-failure-lazy-applied-to-computed-property.png 1424w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/38407/compilation-failure-lazy-applied-to-computed-property.png 2136w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/240a0/compilation-failure-lazy-applied-to-computed-property.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/a8215793ed0c3d4bee40a43cac146b85/690c8/compilation-failure-lazy-applied-to-computed-property.webp\",\n        \"srcSet\": [\"/static/a8215793ed0c3d4bee40a43cac146b85/25c8a/compilation-failure-lazy-applied-to-computed-property.webp 178w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/60698/compilation-failure-lazy-applied-to-computed-property.webp 356w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/690c8/compilation-failure-lazy-applied-to-computed-property.webp 712w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/d7e52/compilation-failure-lazy-applied-to-computed-property.webp 1068w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/456ef/compilation-failure-lazy-applied-to-computed-property.webp 1424w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/2a654/compilation-failure-lazy-applied-to-computed-property.webp 2136w\", \"/static/a8215793ed0c3d4bee40a43cac146b85/08d94/compilation-failure-lazy-applied-to-computed-property.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/a8215793ed0c3d4bee40a43cac146b85/08d94/compilation-failure-lazy-applied-to-computed-property.webp\",\n        \"alt\": \"Lazy cannot be applied to a computed property.\",\n        \"title\": \"Lazy cannot be applied to a computed property.\",\n        \"width\": 712,\n        \"height\": 313,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            Lazy cannot be applied to a computed property.\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `通过这些例子，我们可以了解到 Swift 宏的展开可能会改变源代码的语义。这可能会导致语义冲突，最终使得展开结果无法通过编译。`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `解决方案：渐进式控制宏展开`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `到目前为止，我们已经列出了一系列在实现 Swift 宏时可能会遇到的典型陷阱和缺陷。乍一看，这个列表可能让你感到不知所措。然而，我发明了一种简单的方法来摆脱这些问题：渐进式控制宏展开。这个方法的思想源自于「渐进式暴露 API 设计」和「渐进式类型化」，并借鉴了从苹果 Swift Observation 和 SwiftData 的实现中提取出的一些思路。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `「渐进式控制宏展开」的思想非常简单：如果没有冲突，那么程序员就不需要费力绕过冲突解决机制；如果有，那么我们必须有工具使得程序员可以用最小的努力解决冲突。`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `最大化成为幸运儿的概率`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `如果一个程序员在使用 Swift 宏的过程中不需要解决任何冲突，那么我们可以说该程序员成为了幸运儿。为了最大化 Swift 宏用户获得预期结果的可能性，我们必须遵守以下几点：`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 1：操作控制流的宏应该具有反映这一目的的名称。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这个项目的目的是为了避免对之前提到的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 宏的误用：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  for _ in 0..<10 {\n    #unwrap(bar) {\n      print(bar)\n    }\n  }\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `它被展开为：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  for _ in 0..<10 {\n    // #unwrap 宏展开开始\n    guard let bar = bar else {\n      return\n    }\n    print(bar)\n    // #unwrap 宏展开结束\n  }\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `通过将这个宏重命名为 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#returnIfAnyOptional`), `，程序员就可以更容易地避免进入这个陷阱了。`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 2：如果符合你的设计，可以将宏展开放在一个「保护伞」下面。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这样可以摆脱大多数成员重复声明错误。例如：为了避免 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `#unwrap`), ` 宏中将变量名 shadowing 变成重复声明而引起的命名冲突问题，我们可以使用一个`, React.createElement(MDXTag, {\n      name: \"strong\",\n      components: components,\n      parentName: \"p\"\n    }, `闭包`), `作为「保护伞」来保护宏展开：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `问题展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // \\`updater\\` 第一次被声明\n  let updater = Updater()\n  // #unwrap 宏展开开始\n  guard let bar else {\n    return\n  }\n  // \\`updater\\` 第二次被声明\n  let updater = Updater()\n  print(bar)\n  updater.update()\n  // #unwrap 宏展开结束\n  print(updater.description)\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `使用闭包修复后的宏展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // \\`updater\\` 第一次被声明\n  let updater = Updater()\n  // #unwrap 宏展开开始\n  guard let bar else {\n    return\n  }\n  { (bar) in\n  // \\`updater\\` 第二次被声明\n    let updater = Updater()\n    print(bar)\n    updater.update()\n  }(bar)\n  // #unwrap 宏展开结束\n  print(updater.description)\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，一旦闭包的内容涉及到控制流，闭包将不会在编译优化的性能内联过程中被内联。这会使闭包的内容无法进入宏应用点的局部分析和优化的范围。在某些情况下，这也意味着更大的包体积。为了摆脱这种情况，我们可以使用局部函数而不是闭包，并将局部函数标注为 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@inline(__always)`), ` 来构建「保护伞」。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `使用局部函数修复后的宏展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `func foo(_ bar: Int?) {\n  // \\`updater\\` 第一次被声明\n  let updater = Updater()\n  // #unwrap 宏展开开始\n  guard let bar else {\n    return true\n  }\n  @inline(__always)\n  func unwrapped(bar: Int) -> Void {\n  // \\`updater\\` 第二次被声明\n    let updater = Updater()\n    print(bar)\n    updater.update()\n  }\n  unwrapped(bar)\n  // #unwrap 宏展开结束\n  print(updater.description)\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这种类似「保护伞」的结构也可以用于 attached macro 的宏展开，例如 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏的展开会声明一个嵌套的 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Storage`), ` 类型作为存储类型。这个嵌套类型将起到前面提到的「保护伞」的作用 —— 通过类型作用域保护其成员免受重复声明的影响。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n\n  // @COW 宏展开开始\n  private struct Storage {\n\n    var name: String\n\n    // 其他属性 ...\n\n  }\n\n  // 无关宏展开 ...\n\n  // @COW 宏展开结束\n  \n  // 无关内容 ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 3：使用 fully-qualified name 引用标准库以外的框架中的类型、函数或变量。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在将 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Box`), ` property wrapper 引入 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏展开的示例中，我们会发现 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 本身的名称可能会产生歧义，因为其他被 import 的框架可能有相同名称的声明。我们可以通过使用 fully-qualified name 来解决这个问题。假设库的名称是 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `COW`), `，那么 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Box`), ` 的 fully-qualified name 是 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `COW.Box`), `。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `修复前的宏展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n\n  // @COW 宏展开开始\n\n  // 无关宏展开 ...\n  \n  @Box\n  private var _$storage: Storage\n\n  // 无关宏展开 ...\n\n  // @COW 宏展开结束\n\n  // 无关内容 ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `修复后的宏展开：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\nstruct User {\n\n  // @COW 宏展开开始\n\n  // 无关宏展开 ...\n  \n  @COW.Box\n  private var _$storage: Storage\n\n  // 无关宏展开 ...\n\n  // @COW 宏展开结束\n\n  // 无关内容 ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `最小化解决冲突的工作量`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，我们不能保证程序员总是会遇到幸运的情况。肯定会有一些情况需要程序员自己解决冲突。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `通过应用上述条目，我们仍然可能会遇到潜在的名称和语义冲突。我们唯一能做的就是面对并解决它们：因为我们不能假设一个宏作者能够预测到其他所有宏作者可能选择的名称，同时，不变的语义绝对不应该是 Swift 宏展开的性质，因为这会降低 Swift 宏的灵活性。理想的情况是拥有一组解决冲突的工具，然后这些工具在使用成本方面呈现出平滑曲线。这些工具分别是：`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 4：如果在宏展开的某个部分已由程序员声明，则使用程序员的声明。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `通过这个条目，程序员仍然不需要费力解决冲突。这个条目中描述的机制被一些以 AST 转写的形式实现的语言特性采用，如 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Equatable`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Hashable`), ` —— 如果 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Equatable`), ` 或 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Hashable`), ` 已经由程序员实现，编译器就不会帮程序员实现这些协议。在 Swift Observation 中，当程序员实现了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `access`), ` 函数或 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `withMutation`), ` 函数时，也可以观察到这个现象。由于这个机制是普遍存在的，学习曲线也应该是平缓的。`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 5：在可以重命名声明时，为你的宏展开内容提供重命名的途径。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `我们可以在单个类型上叠加 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@COW`), ` 宏和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@DictionaryLike`), ` 宏的示例来测试此条目。这两个宏的展开会生成两个 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_$storage`), ` 变量。要添加重命名机制，我们可以自然而然地想到在宏中添加一个参数：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@attached(member, names: arbitrary)\n@attached(memberAttribute)\npublic macro COW(storageName: String) =\n  #externalMacro(module: \"COWMacros\", type: \"COWMacro\")\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `但是这会破坏「渐进式控制宏展开」的理念：如果没有冲突，那么程序员就不需要关心解决冲突 —— 有了这个宏声明，程序员每次使用该宏都需要附加一个额外的参数。然而，你可能还不知道，我们可以通过宏重载来解决这个问题。这意味着我们可以有多个同名但具有不同「签名」的宏。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@attached(member, names: arbitrary)\n@attached(memberAttribute)\npublic macro COW() =\n  #externalMacro(module: \"COWMacros\", type: \"COWMacro\")\n\n@attached(member, names: arbitrary)\n@attached(memberAttribute)\npublic macro COW(storageName: String) =\n  #externalMacro(module: \"COWMacros\", type: \"COWMacro\")\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `首先，让我们回顾一下在为每个宏添加重命名机制之前的宏展开。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW\n@DictionaryLike\nstruct User {\n\n  // 其他内容 ...\n\n  // 由 @COW 宏展开引入\n  var _$storage: Storage\n\n  // 由 @DictionaryLike 宏展开引入\n  var _$storage: [String : Any] = [:]\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然后，一下是为每个宏添加重命名机制后的宏展开。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@COW(storageName: \"_$cowStorage\")\n@DictionaryLike(storageName: \"_$dictStorage\")\nstruct User {\n\n  // 其他内容 ...\n\n  // 由 @COW 宏展开引入\n  var _$cowStorage: Storage\n\n  // 由 @DictionaryLike 宏展开引入\n  var _$dictStorage: [String : Any] = [:]\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，宏展开可能会引入无法重命名的声明，比如 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` 和 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `set`), ` accessor。那么接下来我们会遇到最昂贵的条目：`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 6：在生成代码涉及父一级结构中的唯一语言结构时，提供停止代码生成的方法。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Swift Observation 提供了一个很好的例子来说明这一点，下面是示例：一个附着了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Observable`), ` 宏的类，同时其属性也附着了 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Capitalized`), ` property wrapper：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@propertyWrapper\nstruct Capitalized {\n  \n  var wrappedValue: String {\n    didSet {\n      wrappedValue = wrappedValue.capitalized\n    }\n  }\n  \n}\n\n@Observable\nclass User {\n  \n  @Capitalized\n  var name: String\n\n  init(name: String) {\n    self.name = name\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `上面的代码无法编译，因为 property wrapper 要求 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `name`), ` 是一个存储属性，但 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Observable`), ` 将其转换为了计算属性。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/26417a27e9cf5bf2cfb955e35013f678/08d94/compilation-failure-observable-transforms-stored-property-into-computed.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/26417a27e9cf5bf2cfb955e35013f678/0cc25/compilation-failure-observable-transforms-stored-property-into-computed.png\",\n        \"srcSet\": [\"/static/26417a27e9cf5bf2cfb955e35013f678/5116e/compilation-failure-observable-transforms-stored-property-into-computed.png 178w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/92f55/compilation-failure-observable-transforms-stored-property-into-computed.png 356w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/0cc25/compilation-failure-observable-transforms-stored-property-into-computed.png 712w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/7ae06/compilation-failure-observable-transforms-stored-property-into-computed.png 1068w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/eee47/compilation-failure-observable-transforms-stored-property-into-computed.png 1424w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/38407/compilation-failure-observable-transforms-stored-property-into-computed.png 2136w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/240a0/compilation-failure-observable-transforms-stored-property-into-computed.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/26417a27e9cf5bf2cfb955e35013f678/690c8/compilation-failure-observable-transforms-stored-property-into-computed.webp\",\n        \"srcSet\": [\"/static/26417a27e9cf5bf2cfb955e35013f678/25c8a/compilation-failure-observable-transforms-stored-property-into-computed.webp 178w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/60698/compilation-failure-observable-transforms-stored-property-into-computed.webp 356w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/690c8/compilation-failure-observable-transforms-stored-property-into-computed.webp 712w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/d7e52/compilation-failure-observable-transforms-stored-property-into-computed.webp 1068w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/456ef/compilation-failure-observable-transforms-stored-property-into-computed.webp 1424w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/2a654/compilation-failure-observable-transforms-stored-property-into-computed.webp 2136w\", \"/static/26417a27e9cf5bf2cfb955e35013f678/08d94/compilation-failure-observable-transforms-stored-property-into-computed.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/26417a27e9cf5bf2cfb955e35013f678/08d94/compilation-failure-observable-transforms-stored-property-into-computed.webp\",\n        \"alt\": \"@Observable 将存储属性转换为计算属性\",\n        \"title\": \"@Observable 将存储属性转换为计算属性\",\n        \"width\": 712,\n        \"height\": 313,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            @Observable 将存储属性转换为计算属性\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这是宏展开的关键部分：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@Observable\nclass User {\n\n  // 无关宏展开 ...\n  \n  @Capitalized\n  // @Observable 宏展开开始\n  @ObservationTracked\n  // @Observable 宏展开结束\n  var name: String {\n    // @ObservationTracked 宏展开开始\n    init(initialValue) initializes(_name) {\n      _name = initialValue\n    }\n    get {\n      access(keyPath: \\\\.name)\n      return _name\n    }\n    set {\n      withMutation(keyPath: \\\\.name) {\n        _name = newValue\n      }\n    }\n    // @ObservationTracked 宏展开结束\n  }\n  \n  // 无关内容 ...\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `不过，由于 Swift Observation 还提供了一个叫 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@ObservationIgnored`), ` 的 attached macro 来停止 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@Observable`), ` 对应用类型的成员引入的代码生成，我们可以使用这个宏来手动解决冲突。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `首先，我们需要将 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `name`), ` 属性加上 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `_`), ` 前缀，并在其上附着 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@ObservationIgnored`), `。`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@Observable\nclass User {\n  \n  @Capitalized\n  @ObservationIgnored\n  var _name: String\n\n  // ...\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然后，我们可以添加一个 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `name`), ` 属性，手动实现观察机制：`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@Observable\nclass User {\n\n  // ...\n  \n  init(name: String) {\n    self.name = name\n  }\n\n  var name: String {\n    init(initialValue) initializes(__name) {\n      __name = Capitalized(wrappedValue: initialValue)\n    }\n    get {\n      access(keyPath: \\\\.name)\n      return _name\n    }\n    set {\n      withMutation(keyPath: \\\\.name) {\n        _name = newValue\n      }\n    }\n  }\n\n  // ...\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `最终我们解决了这个冲突。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/5ad7cde220f79582ea9e3ced07db71c9/08d94/resolve-observable-transform-computed-property-into-stored.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/5ad7cde220f79582ea9e3ced07db71c9/0cc25/resolve-observable-transform-computed-property-into-stored.png\",\n        \"srcSet\": [\"/static/5ad7cde220f79582ea9e3ced07db71c9/5116e/resolve-observable-transform-computed-property-into-stored.png 178w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/92f55/resolve-observable-transform-computed-property-into-stored.png 356w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/0cc25/resolve-observable-transform-computed-property-into-stored.png 712w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/7ae06/resolve-observable-transform-computed-property-into-stored.png 1068w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/eee47/resolve-observable-transform-computed-property-into-stored.png 1424w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/38407/resolve-observable-transform-computed-property-into-stored.png 2136w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/240a0/resolve-observable-transform-computed-property-into-stored.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/5ad7cde220f79582ea9e3ced07db71c9/690c8/resolve-observable-transform-computed-property-into-stored.webp\",\n        \"srcSet\": [\"/static/5ad7cde220f79582ea9e3ced07db71c9/25c8a/resolve-observable-transform-computed-property-into-stored.webp 178w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/60698/resolve-observable-transform-computed-property-into-stored.webp 356w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/690c8/resolve-observable-transform-computed-property-into-stored.webp 712w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/d7e52/resolve-observable-transform-computed-property-into-stored.webp 1068w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/456ef/resolve-observable-transform-computed-property-into-stored.webp 1424w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/2a654/resolve-observable-transform-computed-property-into-stored.webp 2136w\", \"/static/5ad7cde220f79582ea9e3ced07db71c9/08d94/resolve-observable-transform-computed-property-into-stored.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/5ad7cde220f79582ea9e3ced07db71c9/08d94/resolve-observable-transform-computed-property-into-stored.webp\",\n        \"alt\": \"通过将 @Observable 宏将存储属性转换为计算属性解决冲突\",\n        \"title\": \"通过将 @Observable 宏将存储属性转换为计算属性解决冲突\",\n        \"width\": 712,\n        \"height\": 509,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            通过将 @Observable 宏将存储属性转换为计算属性解决冲突\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `条目 7：宏的文档应包含一个示例宏展开。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `然而，仅仅有第 6 条还不够。程序员仍然可能对如何单独手动「展开」宏感到困惑。为了解决这个问题，宏的作者应该在其文档中包含一个示例实现，展示如何手动展开宏。这样，程序员就能获得他们需要的指导，来手动解决宏展开冲突问题。`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `为什么我不推荐使用 makeUniqueName(_:)`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在 WWDC 2203 中我们了解到有一种方法可以消除名称冲突：使用 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `MacroExpansionContext.makeUniqueName(_:)`), `。然而，此API生成的名称对人类来说是无法理解的。下面是一个例子：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/e524d90a1635f63b290ca091f0b0e5b7/08d94/make-unique-name-result.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/e524d90a1635f63b290ca091f0b0e5b7/0cc25/make-unique-name-result.png\",\n        \"srcSet\": [\"/static/e524d90a1635f63b290ca091f0b0e5b7/5116e/make-unique-name-result.png 178w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/92f55/make-unique-name-result.png 356w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/0cc25/make-unique-name-result.png 712w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/7ae06/make-unique-name-result.png 1068w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/eee47/make-unique-name-result.png 1424w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/38407/make-unique-name-result.png 2136w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/240a0/make-unique-name-result.png 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/e524d90a1635f63b290ca091f0b0e5b7/690c8/make-unique-name-result.webp\",\n        \"srcSet\": [\"/static/e524d90a1635f63b290ca091f0b0e5b7/25c8a/make-unique-name-result.webp 178w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/60698/make-unique-name-result.webp 356w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/690c8/make-unique-name-result.webp 712w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/d7e52/make-unique-name-result.webp 1068w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/456ef/make-unique-name-result.webp 1424w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/2a654/make-unique-name-result.webp 2136w\", \"/static/e524d90a1635f63b290ca091f0b0e5b7/08d94/make-unique-name-result.webp 2144w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/e524d90a1635f63b290ca091f0b0e5b7/08d94/make-unique-name-result.webp\",\n        \"alt\": \"makeUniqueName 生成的名称不可读\",\n        \"title\": \"makeUniqueName 生成的名称不可读\",\n        \"width\": 712,\n        \"height\": 313,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            makeUniqueName 生成的名称不可读\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `你知道这是什么意思吗？至少，我一眼看不出它的含义。我们只能通过使用 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `swift-demangle`), ` 解析它：`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/972a342dc571254d3ef81051934e5b23/cd3ae/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/972a342dc571254d3ef81051934e5b23/0cc25/result-from-swift-demangle-for-make-unqiue-name-generated-names.png\",\n        \"srcSet\": [\"/static/972a342dc571254d3ef81051934e5b23/5116e/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 178w\", \"/static/972a342dc571254d3ef81051934e5b23/92f55/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 356w\", \"/static/972a342dc571254d3ef81051934e5b23/0cc25/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 712w\", \"/static/972a342dc571254d3ef81051934e5b23/7ae06/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 1068w\", \"/static/972a342dc571254d3ef81051934e5b23/eee47/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 1424w\", \"/static/972a342dc571254d3ef81051934e5b23/72a5c/result-from-swift-demangle-for-make-unqiue-name-generated-names.png 1524w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/972a342dc571254d3ef81051934e5b23/690c8/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp\",\n        \"srcSet\": [\"/static/972a342dc571254d3ef81051934e5b23/25c8a/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 178w\", \"/static/972a342dc571254d3ef81051934e5b23/60698/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 356w\", \"/static/972a342dc571254d3ef81051934e5b23/690c8/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 712w\", \"/static/972a342dc571254d3ef81051934e5b23/d7e52/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 1068w\", \"/static/972a342dc571254d3ef81051934e5b23/456ef/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 1424w\", \"/static/972a342dc571254d3ef81051934e5b23/cd3ae/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp 1524w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/972a342dc571254d3ef81051934e5b23/cd3ae/result-from-swift-demangle-for-make-unqiue-name-generated-names.webp\",\n        \"alt\": \"swift-demangle 解析 makeUniqueName 生成的名称的结果\",\n        \"title\": \"swift-demangle 解析 makeUniqueName 生成的名称的结果\",\n        \"width\": 712,\n        \"height\": 518,\n        \"loading\": \"lazy\"\n      }\n    }))), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            swift-demangle 解析 makeUniqueName 生成的名称的结果\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `由于这个名称可能在调试时使用，所以可读性对于理解代码的意图至关重要。这就是为什么我不推荐使用 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `MacroExpansionContext.makeUniqueName(_:)`), ` 的原因。`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `结论`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `在本文中，我们列出了一些编写 Swift 宏时可能遇到的典型陷阱和缺陷。除此之外，我们还讨论了解决它们的方法论：「渐进式控制宏展开」，其中包括 2 个目标和 7 个条目。`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `这个方法论的目标是：`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `如果没有冲突，那么程序员就不需要费力绕过冲突解决机制。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `如果有冲突，则必须有工具允许程序员以最小的努力解决冲突。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `该方法论中的条目包括：`), React.createElement(MDXTag, {\n      name: \"ol\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `操作控制流的宏应该具有反映这一目的的名称。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `如果符合你的设计，可以将宏展开放在一个「保护伞」下面。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `使用 fully-qualified name 引用标准库以外的框架中的类型、函数或变量。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `如果在宏展开的某个部分已由程序员声明，则使用程序员的声明。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `在可以重命名声明时，为你的宏展开内容提供重命名的途径。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `在生成代码涉及父一级结构中的唯一语言结构时，提供停止代码生成的方法。`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `宏的文档应包含一个示例宏展开。`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `此外，我们还了解到 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `MacroExpansionContext.makeUniqueName(_:)`), ` 生成的名称无法被人类理解，这降低了调试时理解代码意图的效率。`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `资源`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `实现了本文中宏的 playground 项目（需要 `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `git checkout traps-and-pitfalls`), `）：`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"href\": \"https://github.com/WeZZard/SwiftMacroRevisited\"\n      }\n    }, `WeZZard/SwiftMacroRevisited`)), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `@COW`), ` 宏的生产级实现：`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"href\": \"https://github.com/wezzard/cowmacro\"\n      }\n    }, `WeZZard/COWMacro`)));\n  }\n\n}\nMDXContent.isMDXComponent = true;","scope":""},"headings":[{"value":"陷阱与缺陷","depth":2},{"value":"控制流的潜在混乱","depth":3},{"value":"Freestanding Macro 中的命名冲突","depth":3},{"value":"Attached Macro 中的命名冲突","depth":3},{"value":"唯一语言结构的命名冲突","depth":3},{"value":"引用其他框架的声明时的命名冲突","depth":3},{"value":"语义冲突","depth":3},{"value":"解决方案：渐进式控制宏展开","depth":2},{"value":"最大化成为幸运儿的概率","depth":3},{"value":"最小化解决冲突的工作量","depth":3},{"value":"为什么我不推荐使用 makeUniqueName(_:)","depth":3},{"value":"结论","depth":2},{"value":"资源","depth":2}]}}},"earlierPostExcerpt":{"slug":"/post/2023/08/swift-macro-revisited-the-strengths-and-essence-a5a4","title":"再探 Swift 宏 - 优势与本质","subtitle":"","createdTime":"2023-08-08T00:00:00.000Z","tags":["Swift","宏"],"category":"编程","file":{"childMdx":{"excerpt":"通过 WWDC 2023，我们了解到 Swift 宏的目标是： 消除重复代码 让繁琐的事情变得简单 以软件包的形式与其他开发者分享 然而，这些目标并不是 Swift 宏所独有的。对于 Swift 中的许多代码重用手段而言，这些都是共同的目标，如函数、类型和模块。可以说，所有高级编程语言都希望实现这些目标。Swift 宏必须在其他方面有所胜出；否则的话没必要存在。 那么， Swift 宏到底擅长什么？ 这个问题的答案至关重要。 Swift 宏独一无二的优势会决定它的本质：这可以指导我们创作有效的 Swift 宏、告诉我们在创作宏时的行为边界，并最终帮助我们产出良好设计的 Swift…"}}},"laterPostExcerpt":{"slug":"/post/2025/03/when-the-swift-compiler-deleted-code-in-stdlib-9067","title":"当 Swift 编译器删除了标准库中的代码 - 记修复 Swift 6 中的冗余 Load 指令消除优化器","subtitle":"","createdTime":"2025-03-09T00:00:00.000Z","tags":["Swift","Compiler"],"category":"Programming","file":{"childMdx":{"excerpt":"最新更新：苹果已接受该问题的修复。最终解决方案在相关代码所有者 review 后进行了调整。 蛇年春节假期前，一位同事向我展示了一个由 use-after-free（释放后使用）错误导致的神秘崩溃。最近，我有时间深入研究这个问题，并发现崩溃是由 Swift 编译器的错误编译引起的。下面是最小复现代码，必须使用  -Osize  优化级别编译。我们可以通过在编译过程中启用地址检查器（address sanitizer）来检测 use-after-free 问题。 有趣的是，将  AutoreleasingUnsafeMutablePointer…"}}}},"pageContext":{"postId":"c743b528-1454-53f9-9a0b-8aebda6e8d68","earlierPostId":"bfebcd5e-37cf-5ace-be71-d0ea1b5d8e48","laterPostId":"46abd102-d678-5362-9d51-00ffd4a02f90"}}