我在Swift中有以下代码:
class VolumeData <T> {
private var volume: [T]
init(with data:Data, width: UInt32, height: UInt32, depth: UInt32) {
let size = width * height * depth
volume = data.arrayFromData(size: Int(size))
}
}
class Volume: NSObject {
private var rawVolume : Data?
public var volume : VolumeData<Any>?
public var header: Header?
....
func loadVolume(_ name: String) {
let filepath = Bundle.main.path(forResource: name, ofType: "vol")
rawVolume = try? Data.init(contentsOf: URL(fileURLWithPath: filepath ?? ""))
header = Header.init(from: ((rawVolume?.subdata(in: 0..<284))!))
let volSize = header!.width * header!.height * header!.depth
switch header!.type {
case .FLOAT:
volume = VolumeData<Float32>(with: (rawVolume?.subdata
(in: 284..<volSize))!, width: header!.width,
height: header!.height, depth: header!.depth)
default:
volume = nil
}
}
}
为了完整起见:
extension Data {
func arrayFromData<T> (size: Int) -> [T] {
var arr:[T] = []
for i in 0..<size {
let offset = 4*i
let d:T = self[offset..<offset+4].withUnsafeBytes { $0.pointee }
arr.append(d)
}
return arr
}
}
现在我有一个编译时错误:
Cannot assign value of type 'VolumeData<Float32>' (aka 'VolumeData<Float>')
to type 'VolumeData<Any>?'
任何人都可以为我指出在Swift中实现这种动态泛型的正确方法吗?
答案 0 :(得分:4)
要在VolumeData
类型之间进行转换,可以始终在项目上使用map
并强制转换:
class VolumeData<T> {
private var volume: [T]
init(with data: Data, width: UInt32, height: UInt32, depth: UInt32) {
let size = width * height * depth
volume = data.arrayFromData(size: Int(size))
}
private init(volume: [T]) {
self.volume = volume
}
func convert<TargetType>(conversionFn: (T) -> TargetType) -> VolumeData<TargetType> {
return VolumeData<TargetType>(volume: self.volume.map(conversionFn))
}
}
然后
case .FLOAT:
let floatVolume = VolumeData<Float32>(
with: (rawVolume?.subdata(in: 284..<volSize))!,
width: header!.width,
height: header!.height,
depth: header!.depth
)
volume = floatVolume.convert { $0 as Any }
但是,VolumeData<Any>
不是很有用,根本没有用。在这种情况下,最好以某种方式保存原始类型。一种简单的方法是enum
,它具有关联的值,例如:
enum VolumeDataType {
case float(volume: VolumeData<Float32>)
}
然后:
class Volume: NSObject {
private var rawVolume: Data?
public var volume: VolumeDataType?
public var header: Header?
func loadVolume(_ name: String) {
let filepath = Bundle.main.path(forResource: name, ofType: "vol")
rawVolume = try? Data(contentsOf: URL(fileURLWithPath: filepath ?? ""))
header = Header(from: ((rawVolume?.subdata(in: 0..<284))!))
let volSize = header!.width * header!.height * header!.depth
switch header!.type {
case .FLOAT:
volume = .float(volume: VolumeData<Float32>(
with: (rawVolume?.subdata(in: 284..<volSize))!,
width: header!.width,
height: header!.height,
depth: header!.depth
))
default:
volume = nil
}
}