swift中Any.Type的大小

时间:2017-12-21 10:00:16

标签: swift

我有一个问题,即将变量的大小声明为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]

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

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

2 个答案:

答案 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()