在数组中给出错误的Swift函数:'@lvalue $ T24'与'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] 

这三种forms的vector[a] = …给我的错误。 任何想法,为什么我得到这个错误?

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

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

我不确定这是否是一个错误。 本能地,如果我传递一个数组到一个函数,我希望能够修改它。 如果我通过inout修饰符,我希望能够使原始variables指向一个新的数组 – 类似于& C修改器在C和C ++中所做的。

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

附录1 – 这不是一个错误

@newacct说这是预期的行为。 经过一番研究,我同意他的看法。 但即使不是我最初认为是错误的错误( 读到最后得出结论 )。

如果我有这样的课程:

 class WithProp { var x : Int = 1 func SetX(newVal : Int) { self.x = newVal } } 

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

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

而不必像以前那样通过实例。 我可以使用inout来创buildavariables来指向另一个实例:

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

使用该代码,在Do2我将p参数(即avariables)指向WithProp的新创build的实例。

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

但是,阅读这本快速书籍的摘录后,一切都得到了澄清

Swift的String,Array和Dictionarytypes被实现为结构体。 这意味着string,数组和字典在分配给新的常量或variables时,或者传递给函数或方法时被复制。

所以当传递给一个func时,它不是原始数组,而是它的一个副本 – 因此,对原始数组做的任何更改(即使可能)都不会完成。

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

非常感谢@newacct 🙂

由于Xcode 6 beta 3,修改Array的内容是一个mutating操作。 你不能修改常量(即let )数组; 你只能修改一个非常量(即var )数组。

函数的参数默认是常量。 因此,不能修改vector的内容,因为它是一个常量。 像其他参数一样,有两种方法可以更改参数:

  • 声明它的var ,在这种情况下,你可以分配给它,但它仍然通过值传递,所以对参数的任何更改不会影响调用范围。
  • 声明它inout ,在这种情况下,参数是通过引用传递的,并且对参数的任何更改就像您对调用作用域中的variables所做的更改一样。

您可以在Swift标准库中看到,所有接受Array并将其改变的函数,如sort() ,都将Array作为inout

PS这就好像数组如何在PHP中工作

编辑:以下为Xcode Beta 2工作。显然,数组的语法和行为已经在Beta 3中更改。如果它是不可变的(一个参数未声明inout或var),您不能再修改具有下标的数组的内容:

不适用于语言的最新更改

我可以在游戏场上工作的唯一方法就是改变你如何声明数组。 我build议尝试这个(在操场上工作):

 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]); 

主要作为未来的参考,@ newacct的答案是正确的。 由于原始post显示了一个返回数组的函数,所以这个问题的正确答案是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 }