我有一个问题,即将变量的大小声明为Any.Type
请参阅以下游乐场代码:
我有这个功能:
func genericSizeMe<T> (_ : T.Type) -> Int
{
return MemoryLayout<T>.size
}
我这样运行:
let size1 = genericSizeMe(UInt32.self) // 4
let size2 = genericSizeMe(UInt16.self) // 2
var type1: UInt32.Type = UInt32.self
let size3 = genericSizeMe(type1) // 4
var type2: UInt16.Type = UInt16.self
let size4 = genericSizeMe(type2) // 2
var type3: Any.Type = UInt32.self
let size5 = genericSizeMe(type3) //ERROR
这给出了错误:
/*
Playground execution failed:
error: MyPlayground.playground:14:13: error: cannot invoke 'genericSizeMe' with an argument list of type '(Any.Type)'
let size5 = genericSizeMe(type3)
^
MyPlayground.playground:14:13: note: expected an argument list of type '(T.Type)'
let size5 = genericSizeMe(type3)
^
*/
如何(如果可能的话)解决这个问题?我想要实现的是拥有一个类型数组,并获得每种类型的大小。像这样:
[UInt32.self, UInt8.self]
循环遍历数组并打印分配每种类型所需的字节大小。
如果更容易,我也可以接受在获得大小之前实际制作每种类型的实例。
答案 0 :(得分:1)
您在使用通用功能时遇到的问题是when a generic placeholder T
is a protocol type P
, T.Type
is not P.Type
; it's P.Protocol
。
因此,您无法将Any.Type
传递给T.Type
参数(虽然Any
在技术上不是协议,但它是一种特殊的内置类型;它具有大多数情况下协议的语义)。您需要传递表示具体类型的元类型。
因此,一种解决方案是为元类型构建类型擦除包装器,如Check whether Swift object is an instance of a given metatype所示:
struct AnyType {
let base: Any.Type
private let _memorySize: () -> Int
private let _memoryStride: () -> Int
private let _memoryAlignment: () -> Int
var memorySize: Int { return _memorySize() }
var memoryStride: Int { return _memoryStride() }
var memoryAlignment: Int { return _memoryAlignment() }
/// Creates a new AnyType wrapper from a given metatype.
/// The passed metatype's value **must** match its static value,
/// i.e `T.self == base` must be `true`.
init<T>(_ base: T.Type) {
precondition(T.self == base, """
The static value \(T.self) and dynamic value \(base) of the \
passed metatype do not match
"""
)
self.base = T.self
self._memorySize = { MemoryLayout<T>.size }
self._memoryStride = { MemoryLayout<T>.stride }
self._memoryAlignment = { MemoryLayout<T>.alignment }
}
}
然后您可以这样使用它:
struct S {
var i: Int
var b: Bool
}
let types = [AnyType(UInt32.self), AnyType(UInt8.self), AnyType(S.self)]
for type in types {
print("Size of \(type.base): \(type.memorySize)")
print("Stride of \(type.base): \(type.memoryStride)")
print("Alignment of \(type.base): \(type.memoryAlignment)")
print()
}
// Size of UInt32: 4
// Stride of UInt32: 4
// Alignment of UInt32: 4
//
// Size of UInt8: 1
// Stride of UInt8: 1
// Alignment of UInt8: 1
//
// Size of S: 9
// Stride of S: 16
// Alignment of S: 8
答案 1 :(得分:0)
最近我从HandyJSON得到了灵感。
protocol AnyExtensions {}
extension AnyExtensions {
public static func getSize() -> Int {
return MemoryLayout<Self>.size;
}
}
func extensions(of type: Any.Type) -> AnyExtensions.Type {
struct Extensions : AnyExtensions {}
var extensions: AnyExtensions.Type = Extensions.self
withUnsafePointer(to: &extensions) { pointer in
UnsafeMutableRawPointer(mutating: pointer).assumingMemoryBound(to: Any.Type.self).pointee = type
}
return extensions
}
只需这样调用即可获得正确的结果:
extensions(of: type).getSize()