已归档:使用 @inlinable

WithSpecializedGenericMacro

swift workflow swift package index swift package index

一个对等宏,用于将泛型 结构体或类 扩展为专门的类型。当您公开带有大量泛型的公共 API,并且知道一些特定的、经常使用的特化时,这有助于 Swift 更好地特化/优化您的代码。 在某种意义上,这个宏使 Swift 中的泛型更像 C++ 模板。

示例

enum Namespace {
  @WithSpecializedGenerics("public typealias Hola<S> = Hello<Int, S>;public typealias Hej<S> = Hello<String, S>")
  final class Hello<T, S>: Identifiable where T: Hashable, S.ID == T, S: Identifiable {
    let id: T
    let children: Hello<T, S>

    let name = #ReplaceWhenSpecializing("Hello!", "\"¡Hola!\"")

    func greeting(with word: Hello<T, S>) -> Hello<T, S> {
      let _: Hello<T, S> = Hello(id: word.id, children: word.children)
      return Hello<T, S>(id: word.id, children: word.children)
    }

    init(id: T, children: Hello<T, S>) {
      self.id = id
      self.children = children.children
    }
  }
}

将被扩展为

enum Namespace {
    
  final class Hello<T, S>: Identifiable where T: Hashable, S.ID == T, S: Identifiable {
    let id: T
    let children: Hello<T, S>

    let name = "Hello!"

    func greeting(with word: Hello<T, S>) -> Hello<T, S> {
      let _: Hello<T, S> = Hello(id: word.id, children: word.children)
      return Hello<T, S>(id: word.id, children: word.children)
    }

    init(id: T, children: Hello<T, S>) {
      self.id = id
      self.children = children.children
    }
  }

  final class Hola<S>: Identifiable where S.ID == Int, S: Identifiable {
    let id: T
    let children: Hola<S>

    let name = "¡Hola!"

    func greeting(with word: Hola<S>) -> Hola<S> {
      let _: Hola<S> = Hola(id: word.id, children: word.children)
      return Hola<S>(id: word.id, children: word.children)
    }
    init(id: T, children: Hola<S>) {
      self.id = id
      self.children = children.children
    }
    public typealias T = Int
  }

  final class Hej<S>: Identifiable where S.ID == String, S: Identifiable {
    let id: T
    let children: Hej<S>

    let name = "¡Hola!"

    func greeting(with word: Hej<S>) -> Hej<S> {
      let _: Hej<S> = Hej(id: word.id, children: word.children)
      return Hej<S>(id: word.id, children: word.children)
    }
    init(id: T, children: Hej<S>) {
      self.id = id
      self.children = children.children
    }
    public typealias T = String
  }
}

由于对等宏无法在全局范围内引入新名称,因此需要 enum Namespace

有关此宏的详细信息

@WithSpecializedGenerics("typealias ...") 接受一个 typealias 语法列表,并容许 final 修饰符。 内部的字符串也 **使用 SwiftSyntax 包进行解析**。 这意味着只要您提供一个可解析的类型别名列表,它就可以工作。 该宏为您执行 6 项操作

该软件包还提供了一个 #ReplaceWhenSpecialing(#OldExpr#, "NewExpr") 宏,它在特化时将所有出现的 #OldExpr# 替换为 NewExpr#OldExpr# 必须是有效的表达式,而 NewExpr 可以是任何字符串。 当您有一些特定的实现时,这会派上用场。

杂项

对于 四叉树数据结构(第 48 行) 中的用例,与直接使用类型别名语法相比,此宏可以将数据结构的构建时间加快约 16%。 诸如遍历树节点之类的用例可以从中获得更多益处。

即使启用了 -cross-module-optimization 标志,我也观察到使用这种方法可以显着提高性能。(在此处的测试用例中,从 0.17 秒到 0.04 秒)

注意

对于泛型函数,请尝试 @_specialize 属性

注意

目前,此宏不特别注意 AnotherNamespace.StructOrClassWithSameName,因此在遇到这种情况时可能会引入不需要的代码。

注意

如果您在同一个文件中向原始泛型类型添加扩展,并且遇到错误 Circular reference,则将扩展移动到另一个文件可以解决此问题。 这可能类似于此处讨论的问题:swiftlang/swift#66450