更新时间:2022-10-14 20:03:48
You're very close, but you don't need a fixed-length tuple. That's what's causing your headaches. Just use an array instead.
@infix func % (values:CVarArg[], format:String) -> String {
return NSString(format:format, arguments:getVaList(values))
}
[M_PI, 6] % "%.3f->%d"
==> "3.142->6"
[M_PI, M_PI_2] % "%.3f %.3f"
==> "3.142 1.571"
Of course this is highly type-unsafe because it's an unchecked printf as you say.
BTW, this even works with mixed-type stuff, and with non-literals:
let x = 1
let y = 1.5
let z = "yes"
[x, y, z] % "%d, %.2f, %@"
==> "1, 1.50, yes"
I don't know if that part is going to be fragile, however. Mixed-type literals are promoted to NSArray
, which seems a dangerous thing to do automatically, so they may change it. But NSArray
is acceptable as a CVarArg[]
.
Note that not all types can be converted this way. Characters currently cannot for instance. You can overcome this by extending them to do so:
extension Character : CVarArg {
func encode() -> Word[] {
var result = Word[]()
let s = String(self)
for c in s.unicodeScalars {
result.append(Word(c.value))
}
return result
}
}
let c:Character = "c"
["I", c, 2*3] % "%@, %lc, %d"
==> "I, c, 6"
I'm wondering if there's an easier way to write encode()
, but I'm not sure yet. Hopefully a Character encoding will be provided by Swift in the future. But the lesson here is that arbitrary types could be given an encode
and be formatted.
class Car {
let make = "Ford"
}
extension Car : CVarArg {
func encode() -> Word[] {
return NSString(string:self.make).encode()
}
}
let car = Car()
[car] % "%@"
The lesson here is that you can turn arbitrary things into a CVarArg
or into any protocol, via extensions.