在 Swift 中对 Array 调用 .count 时分配计数变量
Assign count variable over calling .count on Array in Swift
我偶尔会遇到这样的情况,我不会更改数组的内容,但我需要通过一个函数多次知道它的计数。是把数组的.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
在 performance/codegen 中基本上等同于访问局部变量。
让我们调查一下! myArray.count
等同于访问存储的 属性 还是计算的 属性 执行某些 "unnecessary" 计算(如果对非变异数组重复调用)? (忽略编译器的聪明程度)
/// 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
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
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
struct _SwiftArrayBodyStorage {
__swift_intptr_t count;
__swift_uintptr_t _capacityAndFlags;
};
// Yay, we found a stored property!
所以最后 count
是一个存储的 属性 并且不是每次调用都计算的,所以应该没有理由明确存储 arr.count
属性你自己。
Array.count 是一个预先计算的值。由于它不会即时计算,因此使用它比使用内存再次存储它要少得多。即便如此,这两种方法都不重要,除非以数百万以上的规模进行。
我偶尔会遇到这样的情况,我不会更改数组的内容,但我需要通过一个函数多次知道它的计数。是把数组的.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
在 performance/codegen 中基本上等同于访问局部变量。
让我们调查一下! myArray.count
等同于访问存储的 属性 还是计算的 属性 执行某些 "unnecessary" 计算(如果对非变异数组重复调用)? (忽略编译器的聪明程度)
/// 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
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
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
struct _SwiftArrayBodyStorage { __swift_intptr_t count; __swift_uintptr_t _capacityAndFlags; }; // Yay, we found a stored property!
所以最后 count
是一个存储的 属性 并且不是每次调用都计算的,所以应该没有理由明确存储 arr.count
属性你自己。
Array.count 是一个预先计算的值。由于它不会即时计算,因此使用它比使用内存再次存储它要少得多。即便如此,这两种方法都不重要,除非以数百万以上的规模进行。