是否可以使数组引用不可变,但数组内容可变?

时间:2019-07-10 03:46:46

标签: swift

在Java中,我们可以使用int ans = (42+45-48-5-15+20)*2; // Here---^----------------^ 关键字使数组引用不可变,并使数组内容可变

Java

final

在Swift中,他们更进一步。使用final int[] array = {1, 2, 3}; // Ok. Array content mutable. array[0] = 9; // Compiler error. Array reference immutable. array = new int[]{4, 5, 6}; 关键字,将使数组引用和数组内容不变。

迅速

let

在Swift中,可以使数组引用不可变,但数组内容可变吗?

2 个答案:

答案 0 :(得分:3)

问题的答案是“是”和“否”,取决于您所拥有的。

如果决定声明一个简单的“ let”常量,则无法对其进行修改。 为什么呢因为它可以防止您产生副作用(并且进行了一些优化)。

例如,如果您只想浏览列表并打印值,则无需修改列表。

myArray = [1,2,3]
for element in myArray {
  print(element)
}

为什么会很酷?现在,如果您知道不想修改列表,那么它将阻止您使用可以修改列表的功能。这将节省您的时间,并避免了某些意外行为。 如果您声明var并且不修改值,Swift也会告诉您。

此外,如果您使用结构或类,则Swift中不可变的概念会很有趣。

想象一下,您具有这种结构和此类:

struct TestStruct {
  var myInt: Int

  init(myInt: Int) {
    self.myInt = myInt
  }

}

struct TestClass {
  var myInt: Int

  init(myInt: Int) {
    self.myInt = myInt
  }

}

在此结构中,您有myInt,即var。如果您尝试用一个let常量声明一个TestStructureTestClass对象,会发生什么?

let testStruct = Test(myInt: 3)
// Cannot assign to property: 'test' is a 'let' constant
test.myInt = 5
let testClass = Test(myInt: 3)
// It works
test.myInt = 5

在结构中,let会传播到每个字段,而类不是这种情况。

答案 1 :(得分:1)

  

使用let关键字将使数组引用和数组内容不变。

这是不正确的。这里没有“数组引用”。数组是一个值,就像整数是一个值一样。没有“数组引用”。变量可以是letvar,但这不会改变其值的性质。您不会说var n = 4使“ 4”变了。同样,var ns = [1,2,3]不会使[1,2,3]可变。这仅表示您可以更改ns所指的内容。调用ns.append(5)就像n += 1一样。在每种情况下,它们都分配一个新值。他们不会改变旧值。

作为实现和优化的详细信息,用于ns的基础数组存储可能会被突变并用于新的ns值。但这对呼叫者是不可见的。例如:

var array = [1,2] {
    didSet { print("\(oldValue) -> \(array)") }
}
array.append(1)
array = [1,2,1]

// [1, 2] -> [1, 2, 1]
// [1, 2, 1] -> [1, 2, 1]

追加和分配之间没有深远的区别。他们都是作业。并且请注意,将值设置为相同的值仍然只是一种分配。

我之所以如此,是因为如果您的Java代码依赖于共享的可变状态(程序的一部分修改了数组,而其他部分则应该具有自己的代码),则您不能仅仅通过Java方法进行转换并使其工作参考更新)。但是,如果您的Java以这种方式工作,我建议您改进Java以减少对Java的依赖。只要您通常只传递值和返回值,那么它在Swift中的工作原理与在Java中完全相同。

如果您仍然需要这种可变数组,则可以通过将Array包装在类中来轻松构建一个数组:

final class ArrayRef<Element>: MutableCollection, ExpressibleByArrayLiteral {
    private var elements: [Element] = []

    init(arrayLiteral elements: Element...) {
        self.elements = elements
    }

    var startIndex: Int { elements.startIndex }
    var endIndex: Int { elements.endIndex }
    func index(after i: Int) -> Int { elements.index(after: i) }

    subscript(position: Int) -> Element {
        get { elements[position] }
        set { elements[position] = newValue }
    }
}

let array: ArrayRef = [1, 2, 3]
// Ok. "Array" content mutable.
array[0] = 9
// Compiler error. "Array" is immutable.
array = [4, 5, 6]

(这是一个非常简单且未经优化的实现。通过进行更多工作,您可以使其更高效并改善界面。)

但是除非您确实需要,否则我不建议您这样做。有一个原因它在stdlib中不存在。