不可变的 `var` 数组
Immutable `var` array
我想在 Swift 中创建一个数组,它是不可变的,但可以完全替换,采用函数式编程的风格。
我知道我可以通过这种方式创建它们:
var mutable = [1,2,3] // can change reference, add, remove, etc
let immutable = [4,5,6] // cannot replace reference or add, remove, etc
我想要不变性的属性,但仍然能够更改我的变量指向的不可变数组。例如,我希望这个失败:
myArr.append(42) // fails. immutable array
但我希望这能成功:
// Desired behavior:
// Multiply each element in the immutable array by 2
// Return a new immutable array, assigned to the old var
immutable = immutable.map { [=12=] * 2 } // ERROR: can't replace immutable ref
类似,但不是答案:
- ways to make arrays and collections, but not the kind I'm asking about
- previous language issue that made arrays partially mutable
在这种情况下,let
不能使用,因为它在整个运行时都不会改变。
我个人更喜欢使用 var
并声明一个 NSArray
。您可以重新分配变量以指向另一个不可变 NSArray
,但您不能修改 NSArray
的内容。
陷阱是,如果您设法将其转换为 NSMutableArray
。
,则会导致运行时崩溃
我不知道有什么方法可以使用内置的 Array
类型来实现。
你可以做的是定义一个自定义 ConstantArray
类型
其中 包含 一个数组并且只有不可变的访问器方法
(全部转发到包含的数组):
struct ConstantArray<T> {
private let elements : [T]
// Create with an empty array.
init() {
elements = []
}
// Create with some sequence, e.g.
// let constArray = ConstantArray([1, 2, 3])
init<S : SequenceType where S.Generator.Element == T>(_ s: S) {
elements = Array(s)
}
// Read-only computed property to get the elements.
var array : [T] {
return elements
}
// Some properties you might want to implement:
var count: Int { return elements.count }
var isEmpty: Bool { return elements.isEmpty }
var first: T? { return elements.first }
var last: T? { return elements.last }
}
extension ConstantArray : ArrayLiteralConvertible {
// Create with an array literal, e.g.
// let constArray : ConstantArray = [1, 2, 3]
init(arrayLiteral array: T...) {
elements = array
}
}
// Implement sequence prototol, e.g. for enumeration:
// for elem in myConstantArray { ... }
extension ConstantArray : SequenceType {
func generate() -> IndexingGenerator<[T]> {
return elements.generate()
}
}
// Implement read-only subscripting, e.g.
// let elem = myConstantArray[1]
extension ConstantArray: CollectionType {
var startIndex : Int { return elements.startIndex }
var endIndex : Int { return elements.endIndex }
subscript(index: Int) -> T {
return elements[index]
}
}
extension ConstantArray : Printable {
var description: String { return elements.description }
}
当然这是不同的类型,但是通过实施
SequenceType
和 CollectionType
的用法非常相似。
示例:
var myArr : ConstantArray = [1, 2, 3]
myArr.append(42) // error: 'ConstantArray<Int>' does not have a member named 'append'
myArr[2] = 3 // error: cannot assign to the result of this expression
myArr.array[2] = 3 // error: cannot assign to the result of this expression
myArr = [4, 5, 6] // succeeds
println(myArr) // [4, 5, 6]
for elem in myArr {
println(elem)
}
对于映射,可以使用全局map()
函数
(或 Array
的 map()
方法)并将结果转换回 ConstantArray
:
myArr = ConstantArray(map(myArr) { [=12=] * 2 })
myArr = ConstantArray(myArr.array.map { [=12=] * 2 })
或者您为 ConstantArray
实现一个 map()
方法:
extension ConstantArray {
func map<U>(transform: (T) -> U) -> ConstantArray<U> {
return ConstantArray<U>(elements.map(transform))
}
}
并将其用作
myArr = myArr.map { 2 * [=14=] }
以同样的方式,其他方法如filter()
和sorted()
可以为 ConstantArray
.
实施
你想要的对Array
没有意义,因为它是一个具有值语义的值类型。变量的值是数组——所以改变变量的能力和改变数组的能力在某种程度上是一样的。
语义上没有区别:
myArr.append(42)
和类似的东西(编造的):
myArr = myArr.newArrayWithAppending(42)
在某种程度上,您可以想象 any "modification" 到值类型变量可以实现为为变量分配一个全新的值。 (可能不是那样做,因为效率低下,但是从语义的角度来看,没有理由不能那样实现。)
"mutability"的概念只对引用类型有意义,其中变量是指向实际对象的引用,实际对象可以在多个引用之间共享(因此"mutation" 通过一个引用可以通过另一个看到)。
使用引用类型,你可以做你想做的事,例如一个不可变的 ImmutableArray
class,然后如果你有一个 var
类型的变量 ImmutableArray
,那么你可以构建一个全新的不可变数组并将变量更改为指向新数组,但是任何特定的数组对象都不能是 "changed" 从共享引用中看到的。
我想在 Swift 中创建一个数组,它是不可变的,但可以完全替换,采用函数式编程的风格。
我知道我可以通过这种方式创建它们:
var mutable = [1,2,3] // can change reference, add, remove, etc
let immutable = [4,5,6] // cannot replace reference or add, remove, etc
我想要不变性的属性,但仍然能够更改我的变量指向的不可变数组。例如,我希望这个失败:
myArr.append(42) // fails. immutable array
但我希望这能成功:
// Desired behavior:
// Multiply each element in the immutable array by 2
// Return a new immutable array, assigned to the old var
immutable = immutable.map { [=12=] * 2 } // ERROR: can't replace immutable ref
类似,但不是答案:
- ways to make arrays and collections, but not the kind I'm asking about
- previous language issue that made arrays partially mutable
在这种情况下,let
不能使用,因为它在整个运行时都不会改变。
我个人更喜欢使用 var
并声明一个 NSArray
。您可以重新分配变量以指向另一个不可变 NSArray
,但您不能修改 NSArray
的内容。
陷阱是,如果您设法将其转换为 NSMutableArray
。
我不知道有什么方法可以使用内置的 Array
类型来实现。
你可以做的是定义一个自定义 ConstantArray
类型
其中 包含 一个数组并且只有不可变的访问器方法
(全部转发到包含的数组):
struct ConstantArray<T> {
private let elements : [T]
// Create with an empty array.
init() {
elements = []
}
// Create with some sequence, e.g.
// let constArray = ConstantArray([1, 2, 3])
init<S : SequenceType where S.Generator.Element == T>(_ s: S) {
elements = Array(s)
}
// Read-only computed property to get the elements.
var array : [T] {
return elements
}
// Some properties you might want to implement:
var count: Int { return elements.count }
var isEmpty: Bool { return elements.isEmpty }
var first: T? { return elements.first }
var last: T? { return elements.last }
}
extension ConstantArray : ArrayLiteralConvertible {
// Create with an array literal, e.g.
// let constArray : ConstantArray = [1, 2, 3]
init(arrayLiteral array: T...) {
elements = array
}
}
// Implement sequence prototol, e.g. for enumeration:
// for elem in myConstantArray { ... }
extension ConstantArray : SequenceType {
func generate() -> IndexingGenerator<[T]> {
return elements.generate()
}
}
// Implement read-only subscripting, e.g.
// let elem = myConstantArray[1]
extension ConstantArray: CollectionType {
var startIndex : Int { return elements.startIndex }
var endIndex : Int { return elements.endIndex }
subscript(index: Int) -> T {
return elements[index]
}
}
extension ConstantArray : Printable {
var description: String { return elements.description }
}
当然这是不同的类型,但是通过实施
SequenceType
和 CollectionType
的用法非常相似。
示例:
var myArr : ConstantArray = [1, 2, 3]
myArr.append(42) // error: 'ConstantArray<Int>' does not have a member named 'append'
myArr[2] = 3 // error: cannot assign to the result of this expression
myArr.array[2] = 3 // error: cannot assign to the result of this expression
myArr = [4, 5, 6] // succeeds
println(myArr) // [4, 5, 6]
for elem in myArr {
println(elem)
}
对于映射,可以使用全局map()
函数
(或 Array
的 map()
方法)并将结果转换回 ConstantArray
:
myArr = ConstantArray(map(myArr) { [=12=] * 2 })
myArr = ConstantArray(myArr.array.map { [=12=] * 2 })
或者您为 ConstantArray
实现一个 map()
方法:
extension ConstantArray {
func map<U>(transform: (T) -> U) -> ConstantArray<U> {
return ConstantArray<U>(elements.map(transform))
}
}
并将其用作
myArr = myArr.map { 2 * [=14=] }
以同样的方式,其他方法如filter()
和sorted()
可以为 ConstantArray
.
你想要的对Array
没有意义,因为它是一个具有值语义的值类型。变量的值是数组——所以改变变量的能力和改变数组的能力在某种程度上是一样的。
语义上没有区别:
myArr.append(42)
和类似的东西(编造的):
myArr = myArr.newArrayWithAppending(42)
在某种程度上,您可以想象 any "modification" 到值类型变量可以实现为为变量分配一个全新的值。 (可能不是那样做,因为效率低下,但是从语义的角度来看,没有理由不能那样实现。)
"mutability"的概念只对引用类型有意义,其中变量是指向实际对象的引用,实际对象可以在多个引用之间共享(因此"mutation" 通过一个引用可以通过另一个看到)。
使用引用类型,你可以做你想做的事,例如一个不可变的 ImmutableArray
class,然后如果你有一个 var
类型的变量 ImmutableArray
,那么你可以构建一个全新的不可变数组并将变量更改为指向新数组,但是任何特定的数组对象都不能是 "changed" 从共享引用中看到的。