2017-10-15 106 views
0
轉換一個常量字符串的變量字符串

考慮這個假設斯威夫特功能:在斯威夫特

func putFirst(_ string: String) { 
    var str = string 
    let c = str.popFirst() 
    print(c) 
} 

我所期望的,根據以往的問題,如this one,即str是一個變量,因此可變。然而,str.popFirst()引發編譯錯誤,

Cannot use mutating member on immutable value: 'str' is immutable 

這是我不知道的微妙嗎?這是Swift 4的新行爲嗎?我如何解決它?

+0

'讓C = str.first; str.dropFirst()' – vacawama

回答

1

這是a useless error message;問題是在Collection上只定義了一個popFirst()方法。 Here it is

extension Collection where SubSequence == Self { 
    /// Removes and returns the first element of the collection. 
    /// 
    /// - Returns: The first element of the collection if the collection is 
    /// not empty; otherwise, `nil`. 
    /// 
    /// - Complexity: O(1) 
    @_inlineable 
    public mutating func popFirst() -> Element? { 
    // TODO: swift-3-indexing-model - review the following 
    guard !isEmpty else { return nil } 
    let element = first! 
    self = self[index(after: startIndex)..<endIndex] 
    return element 
    } 
} 

你會發現,它的約束使得CollectionSubSequence本身。這對於String(以及許多其他收集類型,例如ArraySet)是不正確的;但這些類型的切片是正確的。

RangeReplaceableCollection(其String符合)上沒有無限制的過載popFirst()。對此的推理as given by Dave Abrahams in this bug reportpopFirst()應該是O(1);並且在RangeReplaceableCollection上的實現不能保證(實際上對於String,這是線性時間)。

對此的另一個好的理由是as mentioned by Leo Dabus,這是popFirst()不會使集合的索引無效。 RRC的實施將無法保證這一點。

因此,由於語義差異很大,因此不要期望RRC上的popFirst()超載。你總是可以在RRC定義一個不同的名稱方便的方法爲這個雖然:

extension RangeReplaceableCollection { 

    /// Removes and returns the first element of the collection. 
    /// 
    /// Calling this method may invalidate all saved indices of this 
    /// collection. Do not rely on a previously stored index value after 
    /// altering a collection with any operation that can change its length. 
    /// 
    /// - Returns: The first element of the collection if the collection is 
    /// not empty; otherwise, `nil`. 
    /// 
    /// - Complexity: O(n) 
    public mutating func attemptRemoveFirst() -> Element? { 
    return isEmpty ? nil : removeFirst() 
    } 
} 

你會然後說:

func putFirst(_ string: String) { 
    var str = string 
    let c = str.attemptRemoveFirst() 
    print(c) 
}