I want to enforce (compile time) array with 5 elements of a particular type
I couldn't find a solution so resorted to a workaround by creating a tuple
(This is abusive I know)
typealias FiveElementArray = (MyType,MyType,MyType,MyType,MyType) // mock array by using typed tuple
It works for my needs - until I need to access an element by index at runtime.
For instance:
var DB = FiveElementArray // the tuple of 5 elements
tableView(tableView : UITableView,cellForRowAtIndexPath:indexPath) -> UITableViewCell {
// would like to populate with the value at index
DB[indexpath.row] // no such syntax for tuples
}
So how can I use a proper swift Array with statically typed length
The way to prevent unwanted changes on a value type (such as an array) is to put a didSet
observer on it to act as a guard:
var arr = [1, 2, 3, 4, 5] {
didSet {
if arr.count > 5 {arr = oldValue}
}
}
arr.append(6)
println(arr) // [1, 2, 3, 4, 5], that change was illegal
arr[2] = 100
println(arr) // [1, 2, 100, 4, 5], that change was legal
But if that isn't good enough, you'll need to use a wrapper, i.e. has-an array rather than is-an array:
struct FiveElementArray<T> {
private var arr = Array<T>()
// methods for access go here
}
The "methods for access" can include implementations of all the ways of modifying that array that you do permit (e.g. subscripting) and can simply not implement all the ways that you don't permit (e.g. append and extend).
If you insist on a compile-time check, then just stick with your tuple, or even write your own collection. But at that point I think you are just being silly with your requirements. The struct wrapper prevents unwanted changes; thus it is a guarantee, so there is no need to make the guarantee at compile time.
You're probably looking for Dependent Types: It enables you to encode some value (the array length) into the type itself. Luckily it's possible to use dependent types in Swift to some extent.
@oisdk also wrote a blog post where he creates an efficient dependently typed collection structure, you can also read the article while interacting with the code in the Playground version.
Example usage:
func onlySameLength<A, B, L : Nat>(lhs: ConstArray<A, L>, rhs: ConstArray<B, L>) {}
let twoLong = emptyArray() +| 1 +| 2 // [1, 2]
let twoChar = emptyArray() +| "a" +| "b" // ["a", "b"]
onlySameLength(twoLong, rhs: twoChar)
let threeInts = emptyArray() +| 1 +| 2 +| 3 // [1, 2, 3]
//Uncomment for an error
//onlySameLength(twoLong, rhs: threeInts)
I strongly suggest to use Swift's type inference for this one as the type of a ConstArray
with elements String
and count 3
would be ConstArray<String, Succ<SuccSucc<<Zero>>>>
Okay, something like
[1, 2].lazy.filter {$0 == 1 }.flatMap{ [$0] }
has typeLazyCollection<FlattenCollection<LazyMapCollection<LazyFilterCollection<Array<Int>>, [Int]>>>
, so I guessConstArray
isn't too bad :P
来源:https://stackoverflow.com/questions/30035193/swift-create-a-fixed-length-array-enforced-at-compile-time