我对 Swift 语言非常陌生。
我想像在 C++ 中一样声明一个内联func
函数,所以我的声明如下所示:
func MyFunction(param: Int) -> Int {
...
}
我想做这样的事情:
inline func MyFunction(param: Int) -> Int {
...
}
我试图在网上搜索,但我没有找到任何相关的东西,也许没有inline
关键字,但也许有另一种方法可以在 Swift 中内联函数。
我对 Swift 语言非常陌生。
我想像在 C++ 中一样声明一个内联func
函数,所以我的声明如下所示:
func MyFunction(param: Int) -> Int {
...
}
我想做这样的事情:
inline func MyFunction(param: Int) -> Int {
...
}
我试图在网上搜索,但我没有找到任何相关的东西,也许没有inline
关键字,但也许有另一种方法可以在 Swift 中内联函数。
Swift 1.2 将包含@inline
属性,withnever
和__always
as 参数。有关更多信息,请参见此处。
如前所述,您很少需要显式声明函数,@inline(__always)
因为 Swift 在何时内联函数方面非常聪明。但是,在某些代码中可能不需要内联函数。
编辑:Swift 5 添加了该@inlinable
属性。确保你阅读了它,因为可能有一些陷阱可能会导致无法使用。它也仅适用于声明的函数/方法public
,因此它适用于那些希望为那些链接到您的库的人公开内联内容的人。
要使函数内联,只需@inline(__always)
在函数之前添加:
@inline(__always) func myFunction() {
}
但是,值得考虑和了解不同的可能性。有三种可能的内联方式:
@inline(__always)
。使用“如果您的功能相当小,并且您希望您的应用程序运行得更快”。@inline(never)
在函数之前添加来实现。使用“如果你的函数很长并且你想避免增加你的代码段大小”。我遇到了一个我需要使用的问题@inlinable
以及@usableFromInline
Swift 4.2 中引入的属性,所以我想与你分享我的经验。
让我直截了当地说吧,我们的代码库有一个 Analytics Facade 模块,可以链接其他模块。
应用目标 -> 分析外观模块 -> 报告模块 X。
Analytics Facade 模块有一个调用函数report(_ rawReport: EventSerializable)
来触发报告调用,该函数使用来自报告模块 X 的实例来发送特定报告模块 X 的报告调用。
问题是,report(_ rawReport: EventSerializable)
一旦用户启动应用程序,多次调用该函数以发送报告调用会产生不可避免的开销,从而给我们带来很多崩溃。
Optimisation level
此外,如果您将 设置为None
调试模式,重现这些崩溃并不是一件容易的事。就我而言,我只能在将 t 设置Optimisation level
为Fastest, Smalles
t 甚至更高时才能重现它。
解决方案是使用@inlinable
and @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)
}