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] = ... という形式の 3 行でエラーが表示されます。なぜこのエラーが発生するのかについてのアイデアはありますか?

4

4 に答える 4

6

Xcode 6 beta 3 以降、 an の内容を変更することは変更Array操作です。let定数 (つまり) 配列を変更することはできません。非定数 (つまりvar) 配列のみを変更できます。

関数のパラメーターは、既定では定数です。vectorしたがって、定数であるため内容を変更することはできません。他のパラメーターと同様に、パラメーターを変更できるようにする方法は 2 つあります。

  • それを宣言しvarます。この場合、それに割り当てることができますが、それでも値によって渡されるため、パラメーターへの変更は呼び出しスコープに影響しません。
  • Declare it inout、この場合、パラメーターは参照によって渡され、パラメーターへの変更は、呼び出しスコープで変数に変更を加えたのと同じです。

Swift 標準ライブラリで、配列を取り、それを変更するすべての関数 ( などsort()) が配列を として受け取ることがわかりinoutます。

PS これは、ちなみに PHP で配列がどのように機能するかに似ています。

于 2014-07-12T04:54:36.250 に答える
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
}

インスタンスを として渡す必要はありませんinoutinout代わりに使用して、a変数が別のインスタンスを指すようにすることができます。

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

Do2(&a)

そのコードを使用して、内部からDo2パラメーターp(つまり、a変数) が新しく作成された のインスタンスを指すようにしますWithProp

配列では同じことはできません(辞書も同様だと思います)。内部状態を変更する (要素を変更、追加、または削除する) には、inout修飾子を使用する必要があります。それは直感に反していました。

しかし、迅速な本からのこの抜粋を読むと、すべてが明確になります

Swift の String、Array、および Dictionary 型は構造体として実装されます。これは、文字列、配列、および辞書が、新しい定数または変数に割り当てられるとき、または関数またはメソッドに渡されるときにコピーされることを意味します。

そのため、func に渡されると、それは元の配列ではなく、そのコピーになります。したがって、(可能であっても) 変更が元の配列に対して行われることはありません。

結局のところ、上記の私の元の答えは正しく、経験豊富な動作はバグではありません

@newacctに感謝します:)

于 2014-07-11T22:23:31.947 に答える
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 に答える
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 に答える