有没有办法在 Swift 中声明一个内联函数?
Is there a way to declare an inline function in Swift?
我对 Swift 语言还很陌生。
我想像在 C++ 中一样声明一个 inline 函数
所以我的 func
声明如下所示:
func MyFunction(param: Int) -> Int {
...
}
我想做这样的事情:
inline func MyFunction(param: Int) -> Int {
...
}
我试着在网上搜索,但我没有找到任何相关的东西,也许没有 inline
关键字,但也许有另一种方法可以在 Swift.[=15 中内联函数=]
Swift 1.2 将包含 @inline
属性,参数为 never
和 __always
。有关详细信息,请参阅 here。
如前所述,您很少需要将函数显式声明为 @inline(__always)
,因为 Swift 对于何时内联函数相当聪明。但是,在某些代码中可能需要不内联函数。
编辑:Swift 5 添加了 @inlinable
属性。请务必阅读相关内容,因为可能存在一些可能导致无法使用的陷阱。它也仅适用于 functions/methods 声明的 public
,因此它适用于那些想要为那些 link 向您的库公开内联内容的人。
全部归功于, just summarizing the information from the link。
要使函数内联只需在函数前添加 @inline(__always)
:
@inline(__always) func myFunction() {
}
但是,值得考虑和了解不同的可能性。有三种可能的内联方式:
- 有时 - 将确保有时内联函数。这是默认行为,您无需执行任何操作! Swift 编译器可能会自动内联函数作为优化。
- always - 将确保始终内联函数。通过在函数前添加
@inline(__always)
来实现此行为。使用 "if your function is rather small and you would prefer your app ran faster."
- never - 将确保永远不会内联函数。这可以通过在函数前添加
@inline(never)
来实现。使用 "if your function is quite long and you want to avoid increasing your code segment size."
我遇到了一个问题,我需要使用 Swift 4.2 中引入的 @inlinable
和 @usableFromInline
属性,所以我想与您分享我的经验。
但让我直接进入问题,我们的代码库有一个链接其他模块的 Analytics Facade 模块。
App Target -> Analytics Facade 模块 -> Reporting 模块 X.
Analytics Facade 模块有一个名为 report(_ rawReport: EventSerializable)
的函数可以触发报告调用,该函数使用来自报告模块 X 的实例来发送针对特定报告模块 X 的报告调用。
问题是,一旦用户启动应用程序,多次调用 report(_ rawReport: EventSerializable)
函数来发送报告调用会产生不可避免的开销,导致我们发生很多崩溃。
此外,如果您在调试模式下将 Optimisation level
设置为 None
,则重现这些崩溃并非易事。在我的例子中,当我将 Optimisation level
设置为 Fastest, Smalles
t 或更高时,我只能重现它。
解决方案是使用 @inlinable
和 @usableFromInline
。
使用 @inlinable
和 @usableFromInline
将函数体导出为模块接口的一部分,使其在从其他模块引用时可供优化器使用。
@usableFromInline
属性将内部声明标记为模块二进制接口的一部分,允许它在 @inlinable
代码中使用,而不会将其作为模块源接口的一部分公开。
跨模块边界,运行时泛型引入了不可避免的开销,因为必须在函数之间传递具体化的类型元数据,并且必须使用各种间接访问模式来操作泛型类型的值。对于大多数应用程序,与代码本身执行的实际工作相比,这种开销可以忽略不计。
基于此框架构建的客户端二进制文件可以调用这些泛型函数,并且由于消除了抽象开销,因此在启用优化的情况下构建时可能会提高性能。
示例代码:
@inlinable public func allEqual<T>(_ seq: T) -> Bool
where T : Sequence, T.Element : Equatable {
var iter = seq.makeIterator()
guard let first = iter.next() else { return true }
func rec(_ iter: inout T.Iterator) -> Bool {
guard let next = iter.next() else { return true }
return next == first && rec(&iter)
}
return rec(&iter)
}
我对 Swift 语言还很陌生。
我想像在 C++ 中一样声明一个 inline 函数
所以我的 func
声明如下所示:
func MyFunction(param: Int) -> Int {
...
}
我想做这样的事情:
inline func MyFunction(param: Int) -> Int {
...
}
我试着在网上搜索,但我没有找到任何相关的东西,也许没有 inline
关键字,但也许有另一种方法可以在 Swift.[=15 中内联函数=]
Swift 1.2 将包含 @inline
属性,参数为 never
和 __always
。有关详细信息,请参阅 here。
如前所述,您很少需要将函数显式声明为 @inline(__always)
,因为 Swift 对于何时内联函数相当聪明。但是,在某些代码中可能需要不内联函数。
编辑:Swift 5 添加了 @inlinable
属性。请务必阅读相关内容,因为可能存在一些可能导致无法使用的陷阱。它也仅适用于 functions/methods 声明的 public
,因此它适用于那些想要为那些 link 向您的库公开内联内容的人。
全部归功于
要使函数内联只需在函数前添加 @inline(__always)
:
@inline(__always) func myFunction() {
}
但是,值得考虑和了解不同的可能性。有三种可能的内联方式:
- 有时 - 将确保有时内联函数。这是默认行为,您无需执行任何操作! Swift 编译器可能会自动内联函数作为优化。
- always - 将确保始终内联函数。通过在函数前添加
@inline(__always)
来实现此行为。使用 "if your function is rather small and you would prefer your app ran faster." - never - 将确保永远不会内联函数。这可以通过在函数前添加
@inline(never)
来实现。使用 "if your function is quite long and you want to avoid increasing your code segment size."
我遇到了一个问题,我需要使用 Swift 4.2 中引入的 @inlinable
和 @usableFromInline
属性,所以我想与您分享我的经验。
但让我直接进入问题,我们的代码库有一个链接其他模块的 Analytics Facade 模块。
App Target -> Analytics Facade 模块 -> Reporting 模块 X.
Analytics Facade 模块有一个名为 report(_ rawReport: EventSerializable)
的函数可以触发报告调用,该函数使用来自报告模块 X 的实例来发送针对特定报告模块 X 的报告调用。
问题是,一旦用户启动应用程序,多次调用 report(_ rawReport: EventSerializable)
函数来发送报告调用会产生不可避免的开销,导致我们发生很多崩溃。
此外,如果您在调试模式下将 Optimisation level
设置为 None
,则重现这些崩溃并非易事。在我的例子中,当我将 Optimisation level
设置为 Fastest, Smalles
t 或更高时,我只能重现它。
解决方案是使用 @inlinable
和 @usableFromInline
。
使用 @inlinable
和 @usableFromInline
将函数体导出为模块接口的一部分,使其在从其他模块引用时可供优化器使用。
@usableFromInline
属性将内部声明标记为模块二进制接口的一部分,允许它在 @inlinable
代码中使用,而不会将其作为模块源接口的一部分公开。
跨模块边界,运行时泛型引入了不可避免的开销,因为必须在函数之间传递具体化的类型元数据,并且必须使用各种间接访问模式来操作泛型类型的值。对于大多数应用程序,与代码本身执行的实际工作相比,这种开销可以忽略不计。
基于此框架构建的客户端二进制文件可以调用这些泛型函数,并且由于消除了抽象开销,因此在启用优化的情况下构建时可能会提高性能。
示例代码:
@inlinable public func allEqual<T>(_ seq: T) -> Bool
where T : Sequence, T.Element : Equatable {
var iter = seq.makeIterator()
guard let first = iter.next() else { return true }
func rec(_ iter: inout T.Iterator) -> Bool {
guard let next = iter.next() else { return true }
return next == first && rec(&iter)
}
return rec(&iter)
}