Swift 中 Any.Type 的大小

ull*_*trm 5 swift

我在获取声明为的变量的大小时遇到​​问题 Any.Type

请参阅以下游乐场代码:

我有这个功能:

func genericSizeMe<T> (_ : T.Type) -> Int
{
    return MemoryLayout<T>.size
}
Run Code Online (Sandbox Code Playgroud)

我是这样运行的:

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
Run Code Online (Sandbox Code Playgroud)

这给出了错误:

/*

 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)
 ^

 */
Run Code Online (Sandbox Code Playgroud)

如何(如果可能)解决这个问题?我想要实现的是拥有一个类型的数组,并获取每种类型的大小。像这样:

[UInt32.self, UInt8.self]
Run Code Online (Sandbox Code Playgroud)

并循环遍历数组并打印分配每种类型所需的字节大小。


如果更容易,我也可以接受在获取大小之前实际制作每种类型的实例。

Ham*_*ish 1

您在使用通用函数时遇到的问题是,当通用占位符T是协议类型时PT.Type则不是P.Type;它是P.Protocol

因此,您不能将 an 传递Any.TypeT.Type参数(尽管Any从技术上讲它不是协议,但它是一种特殊的内置类型;在大多数情况下它具有协议的语义)。您需要传递代表具体类型的元类型。

因此,一种解决方案是为元类型构建一个类型擦除包装器,如检查 Swift 对象是否是给定元类型的实例所示:

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 }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

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
Run Code Online (Sandbox Code Playgroud)