web-dev-qa-db-ja.com

Swiftにインライン関数を宣言する方法はありますか?

Swift言語に非常に新しい

私はC++のようにインライン関数を宣言したかったので、私の楽しい宣言は

func MyFunction(param: Int) -> Int {
...
...
...
}

そして私はtiのような何かをしたい

inline func MyFunction(param: Int) -> Int {
...
...
...
}

Webで検索しようとしましたが、関連するものは何も見つかりませんでした。おそらくインラインキーワードはありませんが、関数をインライン化する別の方法があるかもしれません。

どうもありがとう :)

34
Gibnem

Swift 1.2には、neverおよび_@inline_をパラメーターとして持つ___always_属性が含まれます。詳細については、 here を参照してください。

前に述べたように、関数を@inline(__always)として明示的に宣言する必要はほとんどありません。なぜなら、Swiftは関数をインライン化するタイミングに関してかなり賢明です。一部のコードでは必要になる場合があります。

45
MaddTheSane

answer へのすべてのクレジット、 link からの情報を要約するだけです。

関数をインラインにするには、関数の前に@inline(__always)を追加するだけです:

_@inline(__always) func myFunction() {

}
_

ただし、さまざまな可能性について検討し、学ぶ価値があります。インライン化には3つの方法があります。

  • sometimes-関数をインライン化することがあります。これはデフォルトの動作であり、何もする必要はありません! Swiftコンパイラーは最適化として関数を自動的にインライン化する場合があります。
  • always-関数を常にインライン化するようにします。関数の前に@inline(__always)を追加して、この動作を実現します。 「機能がかなり小さく、アプリの実行速度が速い場合」を使用します。
  • never-関数をインライン化しないようにします。これは、関数の前に@inline(never)を追加することで実現できます。 「関数が非常に長く、コードセグメントサイズの増加を避けたい場合」を使用します。
14
kgaidis

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)
}
_

詳細-モジュール間のインライン化と特殊化

1
Shady Ghalab