不能对不可变值使用变异成员:函数调用返回不可变值 - 不确定为啥值是不可变的

Posted

技术标签:

【中文标题】不能对不可变值使用变异成员:函数调用返回不可变值 - 不确定为啥值是不可变的【英文标题】:Cannot use mutating member on immutable value: function call returns immutable value - not sure why value is immutable不能对不可变值使用变异成员:函数调用返回不可变值 - 不确定为什么值是不可变的 【发布时间】:2018-01-16 18:38:36 【问题描述】:

对于 Swift 开发来说相对较新。试图修改其他人编写的几个函数。目标是在用户登录后第一次调用此路径时(该部分尚未设置)离开原始路径,并在后续调用中使用另一个路径。

所以在编写将指向第一次或非首次通过的逻辑之前,我正在测试非首次通过逻辑。

这里是 allOfferCards():

func allOfferCards() -> [OfferCard]

    guard dataSource != nil else 
        return []
    

    let numberOfCards = self.dataSource!.kolodaNumberOfCards(self)

    var offerCards = [OfferCard]()

    for i in 0..<numberOfCards 
        let offerCard = viewForCard(at: i)

        if let offerCard = offerCard 
            offerCards.append(offerCard as! OfferCard)
        

    

    return offerCards

这就是我尝试进行更改的地方。原始逻辑反转 allOfferCards() 的返回。我想使用一个名为“shuffle”的自定义函数来随机化数组。

func displayOfferCards() -> Void 
    // What was here originally
    //let offerCards = allOfferCards().reversed()
    var offerCards = allOfferCards().shuffle()

    for (index, offerCard) in offerCards.enumerated() 
        let delay = Double(index) * 0.2
        offerCard.display(delay: delay)
    

这是随机播放功能

extension Array

    /** Randomizes the order of an array's elements. */
    mutating func shuffle()
    
        for _ in 0..<10
        
            sort  (_,_) in arc4random() < arc4random() 
        
    

但是,当我尝试运行此程序时,标题中出现错误 - 无法在不可变值上使用变异成员。但是我不确定为什么 allOfferCards() 会生成一个不可变的值 - var offerCards 是使用 var 关键字定义的,而不是 let 关键字 - 这应该意味着它是可变的正确的?

我在这里做错了什么?

【问题讨论】:

这是一个非常非常糟糕的洗牌算法。 sort 不会将每个元素都与其他元素进行比较,这样做会非常低效。如果它检查并看到a &lt; bc &lt; d,那么它可以检查b &lt; c 以推断a &lt; b &lt; c &lt; d 而无需检查a &lt; ca &lt; d 等等...看看使用适当的Fisher-Yates随机播放:***.com/a/24029847/3141234 @Alexander - 哦,谢谢,我会这样做的。 另外,第一个函数可以简化为两行:gist.github.com/amomchilov/df144a2bee19b627e2163254a42a8a59 我最初没有写它——我们知道有很多逻辑可以重写以提高效率(有些已经有了)。我会看看这个,看看它是否符合我们在这里的计划。 我知道在这样的代码库上工作的感觉,你不想过多地干扰工作状态。幸运的是,这就是我们拥有 VCS 的原因,以保持良好的安全网,防止无意的破坏性更改。但从长远来看,像这样的小增量变化确实会累积并导致实质性改进。我基本上是免费给你的,所以不妨接受它:p 【参考方案1】:

问题是在分配函数的返回值之前,该值本身是不可变的,因此无法直接对其调用变异函数。您应该先将返回值分配给可变变量,然后对其调用变异函数。

func displayOfferCards() -> Void 
    var offerCards = allOfferCards()
    offerCards.shuffle()

    for (index, offerCard) in offerCards.enumerated() 
        let delay = Double(index) * 0.2
        offerCard.display(delay: delay)
    

【讨论】:

这看起来正在运行。我只是要测试一下,我会检查你的答案框。 当我这样做时,我得到元组类型“()”的值没有“枚举”成员。 我在 Playground 中测试了代码(当然注释掉了 viewForCard 等未知函数),它编译得很好。您确定您使用的是完全相同的功能吗? offerCards 的类型是 [OfferCard],所以使用上面的代码你不会得到那个错误。 我绝对在使用上面列出的功能。会不会是 Swift 3 的东西? 您确定您使用的是完全相同的问题吗?仅仅因为在您的new question 中,您执行了var offerCardsShuffled = offerCards.shuffle(),这是错误的,绝对不是我在回答中所显示的。【参考方案2】:

补充@Dávid Pásztoranswer。

您可以使用返回随机副本 (shuffled()) 的变体,而不是使用变异函数 (shuffle()),类似于 sort()sorted()。由于没有变量被改变,它都可以在线完成:

func displayOfferCards() 
    for (index, offerCard) in allOfferCards().shuffled().enumerated() 
        offerCard.display(delay: Double(index) * 0.2)
    

有关shuffle()shuffled() 的实现,请参阅this answer。

【讨论】:

以上是关于不能对不可变值使用变异成员:函数调用返回不可变值 - 不确定为啥值是不可变的的主要内容,如果未能解决你的问题,请参考以下文章

不能对不可变值使用变异 getter:'self' 是不可变错误

Swift 2在协议扩展中使用变异函数时出错“无法在不可变值上使用变异成员:'self'是不可变的

从子视图中更改视图中的数组“不能在不可变值上使用变异成员:'self' 是不可变的”

“结构”的不可变值只有名为“函数”的变异成员

SDK 8.3 不可变值...只有名为“附加”的变异成员

如何使swiftui结构可变