Swift函数接收数组给出错误:' @lvalue $ T24'与CGFloat'不同

时间:2014-07-11 22:00:17

标签: ios arrays swift cgfloat

所以我正在编写一个低通加速度计功能来缓和加速度计的抖动。我有一个CGFloat数组来表示数据,我想用这个函数来阻止它:

// Damps the gittery motion with a lowpass filter.
func lowPass(vector:[CGFloat]) -> [CGFloat]
{
    let blend:CGFloat = 0.2

    // Smoothens out the data input.
    vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
    vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
    vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)

    // Sets the last vector to be the current one.
    lastVector = vector

    // Returns the lowpass vector.
    return vector
}

在这种情况下,lastVector在我的程序顶部定义如下:

var lastVector:[CGFloat] = [0.0, 0.0, 0.0]

表格vector [a]中的三行= ...给我错误。关于我为什么会收到此错误的任何想法?

4 个答案:

答案 0 :(得分:6)

如果使用inout修饰符传递数组,那么代码似乎会编译:

func lowPass(inout vector:[CGFloat]) -> [CGFloat] {
    ...
}

我不确定这是不是一个错误。本能地,如果我将数组传递给函数,我希望能够修改它。如果我使用inout修饰符,我希望能够使原始变量指向一个新数组 - 类似于&修饰符在C和C ++中的作用。 / p>

可能背后的原因是在Swift中有可变和不可变的数组(和字典)。没有inout它被认为是不可变的,因此无法修改它。

附录1 - 这不是错误

@newacct表示预期的行为。经过一番研究,我同意他的观点。但即使不是我最初认为错误的错误(读到最后的结论)。

如果我有这样的课程:

class WithProp {
    var x : Int = 1

    func SetX(newVal : Int) {
        self.x = newVal
    }
}

我可以将该类的实例传递给函数,该函数可以修改其内部状态

var a = WithProp()

func Do1(p : WithProp) {
    p.x = 5 // This works
    p.SetX(10) // This works too
}

,而不必将实例作为inout传递。 我可以使用inout来使a变量指向另一个实例:

func Do2(inout p : WithProp) {
    p = WithProp()
}

Do2(&a)

使用该代码,在Do2内,我将p参数(即a变量)指向新创建的WithProp实例。

对于数组不能做同样的事情(我也假设一个字典)。要更改其内部状态(修改,添加或删除元素),必须使用inout修饰符。这是违反直觉的。

但在阅读快速书籍中的this excerpt之后,一切都得到了澄清

  

Swift的String,Array和Dictionary类型实现为结构。这意味着字符串,数组和字典在分配给新常量或变量时,或者传递给函数或方法时,都会被复制。

因此,当传递给func时,它不是原始数组,而是它的副本 - 因此对其进行的任何更改(即使可能)都不会在原始数组上完成。< / p>

所以,最后,我上面的原始答案是正确,经验丰富的行为不是错误

非常感谢@newacct:)

答案 1 :(得分:6)

从Xcode 6 beta 3开始,修改Array的内容是一种变异操作。您无法修改常量(即let)数组;你只能修改一个非常数(即var)数组。

默认情况下,函数的参数是常量。因此,您无法修改vector的内容,因为它是常量。与其他参数一样,有两种方法可以更改参数:

  • 声明它var,在这种情况下你可以分配它,但它仍然按值传递,因此对参数的任何更改都不会对调用范围产生影响。
  • 声明它inout,在这种情况下参数通过引用传递,对参数的任何更改就像你在调用范围内对变量进行了更改一样。

你可以在Swift标准库中看到所有带有数组并对其进行变异的函数,如sort(),将数组作为inout

P.S。这就像数组如何在PHP中工作一样

答案 2 :(得分:0)

编辑:以下适用于Xcode Beta 2.显然,Beta 3中数组的语法和行为已发生变化。如果数组是不可变的,则不能再使用下标修改数组的内容(参数未声明为inout或VAR):

对语言的最新更改无效

我能让它在游戏场上工作的唯一方法就是改变你如何声明阵列。我建议尝试这个(在游乐场工作):

import Cocoa
let lastVector: CGFloat[] = [0.0,0.0,0.0]

func lowPass(vector:CGFloat[]) -> CGFloat[] {
    let blend: CGFloat = 0.2
    vector[0] = vector[0] * blend + lastVector[0] * ( 1 - blend)
    vector[1] = vector[1] * blend + lastVector[1] * ( 1 - blend)
    vector[2] = vector[2] * blend + lastVector[2] * ( 1 - blend)
    return vector
}

var test = lowPass([1.0,2.0,3.0]);

答案 3 :(得分:0)

主要作为未来参考的后续内容,@ newacct的回答是正确的。由于原始帖子显示了一个返回数组的函数,因此该问题的正确答案是使用var 标记参数:

func lowPass(var vector:[CGFloat]) -> [CGFloat] {
    let blend:CGFloat = 0.2

    // Smoothens out the data input.
    vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
    vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
    vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)

    // Sets the last vector to be the current one.
    lastVector = vector

    // Returns the lowpass vector.
    return vector
}