1

所以我正在编写一个低通加速度计函数来缓和加速度计的抖动。我有一个 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

4 回答 4

6

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

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

我不确定这是否是一个错误。本能地,如果我将一个数组传递给一个函数,我希望能够修改它。如果我使用inout修饰符传递,我希望能够使原始变量指向一个新数组 - 类似于&修饰符在 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) {
    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必须使用修饰符。那是违反直觉的。

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

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

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

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

非常感谢@newacct :)

于 2014-07-11T22:23:31.947 回答
6

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

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

  • 声明它var,在这种情况下你可以给它赋值,但它仍然是按值传递的,所以对参数的任何更改都不会影响调用范围。
  • 声明它inout,在这种情况下,参数是通过引用传递的,对参数的任何更改就像您在调用范围内对变量所做的更改一样。

您可以在 Swift 标准库中看到所有接受 Array 并对其进行变异的函数,例如sort(),将 Array 视为inout.

PS这就像数组在PHP中的工作方式一样

于 2014-07-12T04:54:36.250 回答
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]);
于 2014-07-11T22:30:22.687 回答
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
}
于 2014-10-28T17:13:25.510 回答