Wenn Sie eine Klasse oder einen primitiven Typ an eine Funktion übergeben, wird jede Änderung der Funktion am Parameter außerhalb der Klasse wiedergegeben. Dies ist im Grunde das gleiche, was ein inout
Parameter tun soll.
Was ist ein guter Anwendungsfall für einen inout-Parameter?
Antworten:
inout
bedeutet, dass durch Ändern der lokalen Variablen auch die übergebenen Parameter geändert werden. Ohne sie bleiben die übergebenen Parameter gleich. Versuchen Sie, an den Referenztyp zu denken, wenn Sie ihn verwenden,inout
und an den Werttyp, ohne ihn zu verwenden.Zum Beispiel:
import UIKit var num1: Int = 1 var char1: Character = "a" func changeNumber(var num: Int) { num = 2 print(num) // 2 print(num1) // 1 } changeNumber(num1) func changeChar(inout char: Character) { char = "b" print(char) // b print(char1) // b } changeChar(&char1)
Ein guter Anwendungsfall ist die
swap
Funktion, mit der die übergebenen Parameter geändert werden.Swift 3+ Hinweis : Ab Swift 3 muss das
inout
Schlüsselwort nach dem Doppelpunkt und vor dem Typ stehen. Zum Beispiel benötigt Swift 3+ jetztfunc changeChar(char: inout Character)
.quelle
inout
sie zurückkopiert wird, wenn die Funktion zurückkehrt. Sollte alsochar1
schona
innerhalb der Funktion sein?inout
Sprachreferenz übereinstimmt. Ich werde meiner Antwort ein Beispiel hinzufügen.var
IhrechangeNumber
Funktion in zukünftigen Versionen von Swift nicht mehr unterstützt wird.Aus der Apple-Sprachreferenz: Deklarationen - In-Out-Parameter :
Wenn Sie eine Funktion haben, die einen etwas speichertechnisch großen Werttyp als Argument verwendet (z. B. einen großen Strukturtyp) und denselben Typ zurückgibt, und schließlich die Funktionsrückgabe immer nur zum Ersetzen des Aufruferarguments verwendet wird, dann
inout
ist als zugehörigen Funktionsparameter zu bevorzugen.Betrachten Sie das folgende Beispiel, in dem Kommentare beschreiben, warum wir hier
inout
eine reguläre Type-in-Return-Type-Funktion verwenden möchten :struct MyStruct { private var myInt: Int = 1 // ... lots and lots of stored properties mutating func increaseMyInt() { myInt += 1 } } /* call to function _copies_ argument to function property 'myHugeStruct' (copy 1) function property is mutated function returns a copy of mutated property to caller (copy 2) */ func myFunc(var myHugeStruct: MyStruct) -> MyStruct { myHugeStruct.increaseMyInt() return myHugeStruct } /* call-by-reference, no value copy overhead due to inout opimization */ func myFuncWithLessCopyOverhead(inout myHugeStruct: MyStruct) { myHugeStruct.increaseMyInt() } var a = MyStruct() a = myFunc(a) // copy, copy: overhead myFuncWithLessCopyOverhead(&a) // call by reference: no memory reallocation
Im obigen Beispiel
inout
kann das Ignorieren von Speicherproblemen einfach als gute Code-Praxis bevorzugt werden, um demjenigen, der unseren Code liest, mitzuteilen, dass wir&
das Argument des Funktionsaufrufers mutieren (implizit durch das kaufmännische Und vor dem Argument in der Funktion dargestellt) Anruf). Das Folgende fasst dies ziemlich gut zusammen:Aus dem Apple Language Guide: Funktionen - In-Out-Parameter .
Einzelheiten dazu
inout
und wie es tatsächlich im Speicher behandelt wird (Namecopy-in-copy-out
ist etwas irreführend ...) --- zusätzlich zu den Links zum obigen Sprachhandbuch --- siehe den folgenden SO-Thread:(Zusatz bearbeiten: Ein zusätzlicher Hinweis)
Das Beispiel in der akzeptierten Antwort von Lucas Huang oben versucht, im Rahmen der Funktion mithilfe eines
inout
Arguments auf die Variablen zuzugreifen, die alsinout
Argumente übergeben wurden. Dies wird nicht empfohlen und wird ausdrücklich davor gewarnt, dies in der Sprache ref:Nun ist der Zugriff in diesem Fall "nur" nicht veränderlich, z. B.
print(...)
aber jeder Zugriff wie dieser sollte gemäß Konvention vermieden werden.Auf Anfrage eines Kommentators werde ich ein Beispiel hinzufügen, um zu beleuchten, warum wir mit "dem Wert, der als In-Out-Argument übergeben wurde" eigentlich nichts tun sollten .
struct MyStruct { var myStructsIntProperty: Int = 1 mutating func myNotVeryThoughtThroughInoutFunction (inout myInt: Int) { myStructsIntProperty += 1 /* What happens here? 'myInt' inout parameter is passed to this function by argument 'myStructsIntProperty' from _this_ instance of the MyStruct structure. Hence, we're trying to increase the value of the inout argument. Since the swift docs describe inout as a "call by reference" type as well as a "copy-in-copy-out" method, this behaviour is somewhat undefined (at least avoidable). After the function has been called: will the value of myStructsIntProperty have been increased by 1 or 2? (answer: 1) */ myInt += 1 } func myInoutFunction (inout myInt: Int) { myInt += 1 } } var a = MyStruct() print(a.myStructsIntProperty) // 1 a.myInoutFunction(&a.myStructsIntProperty) print(a.myStructsIntProperty) // 2 a.myNotVeryThoughtThroughInoutFunction(&a.myStructsIntProperty) print(a.myStructsIntProperty) // 3 or 4? prints 3.
In diesem Fall verhält sich das Inout also wie Copy-In-Copy-Out (und nicht als Referenz). Wir fassen zusammen, indem wir die folgende Aussage aus den Sprachreferenzdokumenten wiederholen:
quelle
Do not access the value that was passed as an in-out argument
Aussage zu verstehen . Warum ist das so? Können Sie ein Beispiel geben? Soweit ich weiß, wird zuerst innerhalb der Funktion auf ein Argument zugegriffen, egal ob inout oder nicht, andernfalls benötigen wir das Argument überhaupt nicht.Funktionsparameter sind standardmäßig Konstanten. Der Versuch, den Wert eines Funktionsparameters aus dem Hauptteil dieser Funktion heraus zu ändern, führt zu einem Fehler bei der Kompilierung. Dies bedeutet, dass Sie den Wert eines Parameters nicht versehentlich ändern können. Wenn eine Funktion den Wert eines Parameters ändern soll und diese Änderungen nach Beendigung des Funktionsaufrufs beibehalten werden sollen, definieren Sie diesen Parameter stattdessen als In-Out-Parameter.
quelle
Mit dem Parameter inout können wir die Daten eines Werttypparameters ändern und Änderungen nach Abschluss des Funktionsaufrufs beibehalten.
quelle
Wenn Sie mit Klassen arbeiten, können Sie die Klasse wie gesagt ändern, da der Parameter eine Referenz auf die Klasse ist. Dies funktioniert jedoch nicht, wenn Ihr Parameter ein Werttyp ist ( https://docs.swift.org/swift-book/LanguageGuide/Functions.html - Abschnitt "In-Out-Parameter").
Ein gutes Beispiel für die Verwendung von inout ist dieses (Definition von Mathematik für CGPoints):
func + (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x + right.x, y: left.y + right.y) } func += (left: inout CGPoint, right: CGPoint) { left = left + right }
quelle
Grundsätzlich ist es nützlich, wenn Sie mit Adressen von Variablen spielen möchten, was in Datenstrukturalgorithmen sehr nützlich ist
quelle
bei Verwendung des Inout-Parameters Swift 4.0 Work
class ViewController: UIViewController { var total:Int = 100 override func viewDidLoad() { super.viewDidLoad() self.paramTotal(total1: &total) } func paramTotal(total1 :inout Int) { total1 = 111 print("Total1 ==> \(total1)") print("Total ==> \(total)") } }
quelle