在Swift中对Array调用.count时分配count变量



我偶尔会去一个地方,在那里我不会更改数组的内容,但我需要在函数中多次知道它的计数。将数组的.count分配给变量并多次使用它是否更有效,或者编译器是否使效率等效?

让我们调查一下!myArray.count是否等效于访问存储的属性,或者如果对非变异数组重复调用,它是否是执行一些"不必要"计算的计算属性?(无视编译器的聪明(

  • swift/stdlib/public/core/Arrays.swift.gib
/// The number of elements in the array.
public var count: Int {
  return _getCount()
}
// ... what is function _getCount()?
internal func _getCount() -> Int {
  return _buffer.count
}
// ... what is property _buffer?
internal var _buffer: _Buffer
// ... what is type _Buffer? (Swift)
internal typealias _Buffer = _ContiguousArrayBuffer<Element>
// ... what is type _ContiguousArrayBuffer?
// --> switch source file
  • swift/stdlib/public/core/ContiquentArrayBuffer.swift
import SwiftShims
/// Class used whose sole instance is used as storage for empty
/// arrays.  The instance is defined in the runtime and statically
/// initialized.  See stdlib/runtime/GlobalObjects.cpp for details.
internal struct _ContiguousArrayBuffer<Element> : _ArrayBufferProtocol {
  // ... conformance to _ArrayBufferProtocol
  /// The number of elements the buffer stores.
  internal var count: Int {
    get {
      return __bufferPointer.header.count
    }
    // ...
  }   
  // ...
}
// ... what is property __bufferPointer?
var __bufferPointer: ManagedBufferPointer<_ArrayBody, Element>
// what is type _ArrayBody?
// we notice for now that it is used in the following class:
internal final class _EmptyArrayStorage
  : _ContiguousArrayStorageBase {
  // ...
  var countAndCapacity: _ArrayBody // telling name for a tuple? :)
}
// --> proceed to core/ArrayBody.swift
  • swift/stdlib/public/core/ArrayBody.swift
import SwiftShims
// ...
internal struct _ArrayBody {
  var _storage: _SwiftArrayBodyStorage
  // ...
  /// The number of elements stored in this Array.
  var count: Int {
    get {
      return _assumeNonNegative(_storage.count)
    }
    set(newCount) {
      _storage.count = newCount
    }
  } 
}
// we are near our price! we need to look closer at  _SwiftArrayBodyStorage, 
// the type of _storage, so lets look at SwiftShims, GlobalObjects.cpp
// (as mentioned in source comments above), specifically
// --> switch source file
  • swift/stdlib/public/SwiftShims/GlobalObjects.h
struct _SwiftArrayBodyStorage {
  __swift_intptr_t count;              
  __swift_uintptr_t _capacityAndFlags;
};
// Yay, we found a stored property!

因此,最终count是一个存储的属性,并且不是每次调用都计算的,因此不应该自己显式存储arr.count属性。

struct _SwiftArrayBodyStorage {
    __swift_intptr_t count;
    __swift_uintptr_t _capacityAndFlags;
};

这是Swift实现的结构。根据这个计数,是否一直知道缓冲区中有多少元素。你可能可以使用

信息表单:https://ankit.im/swift/2016/01/08/exploring-swift-array-implementation/

编辑以获取更多信息

public var count: Int {
  get {
    return __bufferPointer.value.count
  }
  nonmutating set {
     _sanityCheck(newValue >= 0)
     _sanityCheck(
        newValue <= capacity,
        "Can't grow an array buffer past its capacity")
        __bufferPointer._valuePointer.memory.count = newValue
    }
}

这没关系;我建议做任何能让代码更简单、更容易理解的事情。在版本构建中,优化器应该内联,并注意到调用之间的值是相同的。无论如何,Array.count在性能/代码生成方面基本上等同于访问局部变量。

Array.count是一个预先计算的值。由于它不是动态计算的,因此使用它所需的工作量远小于使用内存第二次存储它所需。即便如此,这两种方法都不重要,除非以数百万美元以上的价格完成。

最新更新