将变量赋值给函数中的类型,我如何使类型本身成为描述变量输出类型的输入?:斯威夫特



我创建了一个包含数据、偏移量和读取方法的文件读取结构体(不知怎么的,fread()让我感到困惑)。

我已经让它工作了,现在想要实现一个方法,它将采用n x m矩阵项并输出一个值矩阵。(类似于matlab中的read(FileID, [n m], "(datatype)"))

这是我的想法

// should be able to handle all sorts of datatypes and output n by m matrix.
mutating func matRead( dim : [[Int]], dtype : Int ){
if dim.count != 2{
fatalError("Dimensions dont match "n by m" in matRead")
}
// make sure to preallocate with zeros.

var mat_Out : typecast[dtype][2].self = []

}

我有一个类型转换字典,看起来是这样的

// typecast dictionary key : [ array_type, byte, element_type ]
let typecast : [Int16:[Any]] = [ 1: [ [UInt8].self  , 1, "uint8"],
2: [ [UInt16].self , 2, "uint16"],  // use .self to reference data type itself.
3: [ [UInt32].self , 4, "uint32"],
4: [ [Int8].self   , 1, "int8"  ],
5: [ [Int16].self  , 2, "int16" ],
6: [ [Int32].self  , 4, "int32" ],
7: [ [Float32].self, 4, "float32"],
8: [ [Float64].self, 8, "float64"],
12:[ [Int32].self  , 4, "int32" ]   ]

问题来了:matRead()函数的第8行不起作用。Swift不理解我试图使用类型转换字典将输出矩阵赋值给一个新的数组类型。我也试过&;as&;var mat_Out : Any = [] as typecast[dtype][0],也是同样的错误(Swift编译器认为我的意思是把括号放在外面)。

或者我可以走很长的路,根据字符串值手动进行类型转换(已经必须这样做了:参见下面的readstruct代码),但是如果有另一种方法,它将极大地节省时间。


下面的filerereading结构体(冗余使用检查计数,但我没有清理它)

struct fRead {
var off : Int = 0
let data : Data

mutating func resetOffsetToZero() {
off = 0
}

mutating func setOffset( _ to : Int ) {
off.self = to
}
mutating func moveOffset( _ by : Int) {
off.self += by
}
func getOffset() -> Int {
return off
}
// reading without specified number of elements defaults to 1.
// these mutating funcs vary only in their output type and byte offset size.
mutating func int32Read(count : Int = 1) -> [Int32] {
var int32out : [Int32] = []
if count > 1 {
for i in 0...count-1 {
int32out.append( Int32( data.subdata(in: off + i * 4..<(off + (i + 1) * 4) ).withUnsafeBytes{ $0.load(as: Int32.self )} ))
}
off += count * 4
}
else if count == 1 {
int32out =  [ Int32( data.subdata(in: off..<(off+4) ).withUnsafeBytes{ $0.load(as: Int32.self )} )]
off += 4
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint32Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int32out
}

mutating func int16Read(count : Int = 1) -> [Int16] {
var int16out : [Int16] = []
if count > 1 {
for i in 0...count-1 {
int16out.append( data.subdata(in: off + i * 2..<(off + (i + 1) * 2) ).withUnsafeBytes{ $0.load(as: Int16.self )} )
}
off += count * 2
}
else if count == 1 {
int16out =  [ data.subdata(in: off..<(off+2) ).withUnsafeBytes{ $0.load(as: Int16.self )} ]
off += 2
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int16out
}

mutating func float64Read(count : Int = 1) -> [Float64] {
var float64out : [Float64] = []
if count > 1 {
for i in 0...count-1 {
float64out.append( data.subdata(in: off + i * 8..<(off + (i + 1) * 8) ).withUnsafeBytes{ $0.load(as: Float64.self )} )
}
off += count * 8
}
else if count == 1 {
float64out =  [ data.subdata(in: off..<(off+8) ).withUnsafeBytes{ $0.load(as: Float64.self )} ]
off += 8
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return float64out
}

mutating func uint32Read(count : Int = 1) -> [UInt32] {
var uint32out : [UInt32] = []
if count > 1 {
for i in 0...count-1 {
uint32out.append( data.subdata(in: off + i * 4..<(off + (i + 1) * 4) ).withUnsafeBytes{ $0.load(as: UInt32.self )} )
}
off += count * 4
}
else if count == 1 {
uint32out =  [ data.subdata(in: off..<(off+4) ).withUnsafeBytes{ $0.load(as: UInt32.self )} ]
off += 4
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return uint32out
}

mutating func int64Read(count : Int = 1) -> [Int64] {
var int64out : [Int64] = []
if count > 1 {
for i in 0...count-1 {
int64out.append( Int64( data.subdata(in: off + i * 4..<(off + (i + 1) * 8) ).withUnsafeBytes{ $0.load(as: Int64.self )} ))
}
off += count * 8
}
else if count == 1 {
int64out =  [ Int64( data.subdata(in: off..<(off+8) ).withUnsafeBytes{ $0.load(as: Int64.self )} )]
off += 8
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint64Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int64out
}
// should be able to handle all sorts of datatypes and output n by m matrix.
mutating func matRead( dim : [[Int]], dtype : Int ){
if dim.count != 2{
fatalError("Dimensions dont match "n by m" in matRead")
}
// make sure to preallocate with zeros.

var mat_Out : Any = [] as typecast[dtype][0]

}
}
// I only discovered afterwards that 0...0 range works! So all the testing for  ==1 , == 0 wasn't necessary

难道通用的解决方案不是最好的方法吗?下面是元素为整数时的泛型版本,因此对于浮点数(BinaryFloatingPoint)需要类似的函数。

mutating func matRead<T: BinaryInteger>(count: Int = 1) -> [T] {
var intOut : [T] = []
let width = T().bitWidth / 8
if count > 1 {
for i in 0...count-1 {
intOut.append( T( data.subdata(in: off + i * 4..<(off + (i + 1) * width) ).withUnsafeBytes{ $0.load(as: T.self )} ))
}
off += count * width
}
else if count == 1 {
intOut =  [ T( data.subdata(in: off..<(off+width) ).withUnsafeBytes{ $0.load(as: T.self )} )]
off += width
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint64Read( count : Int = 1) called with a negative count, returning empty array.")
}
return intOut
}

注意这里有一个"bug"。在上面的代码中,我不确定在i * 4..<(off + (i + 1)中用什么代替4,因为你在函数之间使用了这个数字,所以不一致。我猜应该是width / 2,但我把它留给你来更新那部分。

最新更新