Rekursionen: Unterschied zwischen den Versionen
Pwania (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „Eine weitere Form der Schleife, also des wiederholten Aufrufs eines Programmteils, kann dadurch erfolgen, dass eine Prozedur sich selbst aufruft und somit eine…“) |
Pwania (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
Eine weitere Form der Schleife, also des wiederholten Aufrufs eines Programmteils, kann dadurch erfolgen, dass eine Prozedur sich selbst aufruft und somit eine Wiederholung erwirkt. Wenn Sie eine Rekursion einsetzen, erzeugen Sie eine Endlosschleife (siehe [[Fehlermeldungen#28: Nicht genügend Stapelspeicher|Laufzeitfehler 28: Nicht genügend Stapelspeicher]]) und müssen daher eine sehr klare Abbruchbedingung schaffen oder nur in einem klar definierten Fall den erneuten Aufruf bewirken. ;Beispiel Im folgenden Beispiel sollen mehrere aufeinander folgende Leerzeichen auf ein einziges reduziert werden. Würde man das Ersetzen von doppelten Leerzeichen nur einmal durchführen, würden zum Beispiel von drei aufeinander folgenden Leerzeichen immer noch zwei Leerzeichen übrig bleiben (die Replace-Funktion ersetzt die ersten beiden mit einem einzelnen Leerzeichen, kehrt jedoch nicht nochmal zurück und erkennt, dass dadurch immer noch zwei Leerzeichen hintereinander stehen). In der Funktion 'SingularizeSpaces' wird also zuerst das Ersetzen von doppelten Leerzeichen durchgeführt. Danach wird geprüft, ob immer noch doppelte Leerzeichen vorhanden sind. Ist dies der Fall, ruft die Funktion sich selbst mit dem schon einmal vorbereiteten Text auf. Am Schluss wird der Text als Rückgabewert der Funktion zurückgegeben. Public Function SingularizeSpaces(ByVal strText As String) strText = Replace(strText, " ", " ") If InStr(strText, " ") > 0 Then strText = SingularizeSpaces(strText) End If SingularizeSpaces = strText End Function | [[Category:vba-wiki]] | ||
Eine weitere Form der Schleife, also des wiederholten Aufrufs eines Programmteils, kann dadurch erfolgen, dass eine Prozedur sich selbst aufruft und somit eine Wiederholung erwirkt. | |||
Wenn Sie eine Rekursion einsetzen, erzeugen Sie eine Endlosschleife (siehe [[Fehlermeldungen#28: Nicht genügend Stapelspeicher|Laufzeitfehler 28: Nicht genügend Stapelspeicher]]) und müssen daher eine sehr klare Abbruchbedingung schaffen oder nur in einem klar definierten Fall den erneuten Aufruf bewirken. | |||
== Gezielte Rekursion == | |||
Bei der gezielten Rekursion setzen Sie die Wiederholung einer gesamten Prozedur bewusst und gewollt ein, um dadurch das gewünschte Ergebnis zu erreichen. | |||
;Beispiel | |||
Im folgenden Beispiel sollen mehrere aufeinander folgende Leerzeichen auf ein einziges reduziert werden. Würde man das Ersetzen von doppelten Leerzeichen nur einmal durchführen, würden zum Beispiel von drei aufeinander folgenden Leerzeichen immer noch zwei Leerzeichen übrig bleiben (die Replace-Funktion ersetzt die ersten beiden mit einem einzelnen Leerzeichen, kehrt jedoch nicht nochmal zurück und erkennt, dass dadurch immer noch zwei Leerzeichen hintereinander stehen). | |||
In der Funktion 'SingularizeSpaces' wird also zuerst das Ersetzen von doppelten Leerzeichen durchgeführt. Danach wird geprüft, ob immer noch doppelte Leerzeichen vorhanden sind. Ist dies der Fall, ruft die Funktion sich selbst mit dem schon einmal vorbereiteten Text auf. Am Schluss wird der Text als Rückgabewert der Funktion zurückgegeben. | |||
<span style="Color:blue">Public Function </span>SingularizeSpaces<span style="Color:gray">(</span><span style="Color:blue">ByVal </span>strText<span style="Color:blue"> As String</span><span style="Color:gray">)</span> | |||
strText <span style="Color:gray">=</span> Replace<span style="Color:gray">(</span>strText<span style="Color:gray">,</span> <span style="Color:gray">" ",</span> <span style="Color:gray">" ")</span> | |||
<span style="Color:blue"> If </span>InStr<span style="Color:gray">(</span>strText<span style="Color:gray">,</span> <span style="Color:gray">" ")</span> <span style="Color:gray">></span> <span style="Color:gray">0</span><span style="Color:blue"> Then</span> | |||
strText <span style="Color:gray">=</span> SingularizeSpaces<span style="Color:gray">(</span>strText<span style="Color:gray">)</span> | |||
<span style="Color:blue"> End If</span> | |||
SingularizeSpaces <span style="Color:gray">=</span> strText<span style="Color:blue"> | |||
End Function</span> | |||
== Ungeplante Rekursion == | |||
In bestimmten Situationen können Rekursionen ohne Ihren Einfluss und somit ungeplant auftreten. Da diese zu Überläufen führen, gilt es, eigene Abbruchkriterien einzubeziehen. | |||
;Beispiel | |||
Sie arbeiten an einem Dialog, bei dem zwei Listenfelder miteinander syncronisiert werden sollen. Wenn der Anwender in einem Listenfeld eine Auswahl trifft, soll diese auf das andere Listenfeld übertragen werden und umgekehrt. | |||
Die ungeplante Rekursion entsteht dadurch, dass die programmatische Auswahl eines Eintrages in einem Listenfeld in diesem ebenfalls das Ereignis auslöst, welches eine Änderung der Auswahl bedeutet. | |||
Ein Lösungsansatz könnte wie folgt aussehen: | |||
* Eine gemeinsame Prozedur anlegen, welche die Auswahl der Einträge zentral übernehmen wird | |||
<span style="Color:blue">Private Sub </span>SelectEntry<span style="Color:gray">(</span><span style="Color:blue">ByVal </span>strValue<span style="Color:blue"> As String</span><span style="Color:gray">)</span> | |||
<span style="Color:blue"> | |||
End Sub</span> | |||
* Im 'Change'-Ereignis der gewünschten Listenfelder wird diese Prozedur mit dem aktuellen Wert aufgerufen | |||
<span style="Color:blue">Private Sub </span>lbxListbox01_Change<span style="Color:gray">()</span> | |||
SelectEntry lbxListbox01.Value<span style="Color:blue"> | |||
End Sub</span> | |||
<span style="Color:blue">Private Sub </span>lbxListbox02_Change<span style="Color:gray">()</span> | |||
SelectEntry lbxListbox02.Value<span style="Color:blue"> | |||
End Sub</span> | |||
' ... | |||
* In der gemeinsamen Prozedur verhindert eine [[Variablen#Statische_prozedurale_Variable|statische Variable]] das wiederholte Ausführen der Prozedur, während sie das erste Mal ausgeführt wird | |||
<span style="Color:blue">Private Sub </span>SelectEntry<span style="Color:gray">(</span><span style="Color:blue">ByVal </span>strValue<span style="Color:blue"> As String</span><span style="Color:gray">)</span> | |||
<span style="Color:blue"> Static </span>blnBusy<span style="Color:blue"> As Boolean</span> | |||
<span style="Color:blue"> If </span>blnBusy <span style="Color:gray">=</span><span style="Color:blue"> True Then Exit Sub </span> <span style="Color:green">' hiermit wird verhindert, dass diese prozedur ein weiteres mal ausgeführt wird!</span> | |||
blnBusy <span style="Color:gray">=</span><span style="Color:blue"> True</span> | |||
<span style="Color:green">' evt prüfen ob werte in listenfeldern vorhanden ist</span> | |||
lbxListbox<span style="Color:gray">01.</span>Value <span style="Color:gray">=</span> strValue | |||
lbxListbox<span style="Color:gray">02.</span>Value <span style="Color:gray">=</span> strValue | |||
blnBusy <span style="Color:gray">=</span><span style="Color:blue"> False | |||
End Sub</span> | |||
Da der Wert einer statischen Variable für jeden Durchlauf der Prozedur erhalten bleibt (in diesem Falle solange der Dialog existiert), kann mit deren Hilfe verhindert werden, dass die Prozedur mehr als einmal durchlaufen wird, sobald der erste Durchlauf gestartet wurde. Siehe auch [[Variablen#Statische_prozedurale_Variable|Statische prozedurale Variable]]. |
Aktuelle Version vom 28. Januar 2023, 00:36 Uhr
Eine weitere Form der Schleife, also des wiederholten Aufrufs eines Programmteils, kann dadurch erfolgen, dass eine Prozedur sich selbst aufruft und somit eine Wiederholung erwirkt.
Wenn Sie eine Rekursion einsetzen, erzeugen Sie eine Endlosschleife (siehe Laufzeitfehler 28: Nicht genügend Stapelspeicher) und müssen daher eine sehr klare Abbruchbedingung schaffen oder nur in einem klar definierten Fall den erneuten Aufruf bewirken.
Gezielte Rekursion
Bei der gezielten Rekursion setzen Sie die Wiederholung einer gesamten Prozedur bewusst und gewollt ein, um dadurch das gewünschte Ergebnis zu erreichen.
- Beispiel
Im folgenden Beispiel sollen mehrere aufeinander folgende Leerzeichen auf ein einziges reduziert werden. Würde man das Ersetzen von doppelten Leerzeichen nur einmal durchführen, würden zum Beispiel von drei aufeinander folgenden Leerzeichen immer noch zwei Leerzeichen übrig bleiben (die Replace-Funktion ersetzt die ersten beiden mit einem einzelnen Leerzeichen, kehrt jedoch nicht nochmal zurück und erkennt, dass dadurch immer noch zwei Leerzeichen hintereinander stehen).
In der Funktion 'SingularizeSpaces' wird also zuerst das Ersetzen von doppelten Leerzeichen durchgeführt. Danach wird geprüft, ob immer noch doppelte Leerzeichen vorhanden sind. Ist dies der Fall, ruft die Funktion sich selbst mit dem schon einmal vorbereiteten Text auf. Am Schluss wird der Text als Rückgabewert der Funktion zurückgegeben.
Public Function SingularizeSpaces(ByVal strText As String) strText = Replace(strText, " ", " ") If InStr(strText, " ") > 0 Then strText = SingularizeSpaces(strText) End If SingularizeSpaces = strText End Function
Ungeplante Rekursion
In bestimmten Situationen können Rekursionen ohne Ihren Einfluss und somit ungeplant auftreten. Da diese zu Überläufen führen, gilt es, eigene Abbruchkriterien einzubeziehen.
- Beispiel
Sie arbeiten an einem Dialog, bei dem zwei Listenfelder miteinander syncronisiert werden sollen. Wenn der Anwender in einem Listenfeld eine Auswahl trifft, soll diese auf das andere Listenfeld übertragen werden und umgekehrt.
Die ungeplante Rekursion entsteht dadurch, dass die programmatische Auswahl eines Eintrages in einem Listenfeld in diesem ebenfalls das Ereignis auslöst, welches eine Änderung der Auswahl bedeutet.
Ein Lösungsansatz könnte wie folgt aussehen:
- Eine gemeinsame Prozedur anlegen, welche die Auswahl der Einträge zentral übernehmen wird
Private Sub SelectEntry(ByVal strValue As String) End Sub
- Im 'Change'-Ereignis der gewünschten Listenfelder wird diese Prozedur mit dem aktuellen Wert aufgerufen
Private Sub lbxListbox01_Change() SelectEntry lbxListbox01.Value End Sub Private Sub lbxListbox02_Change() SelectEntry lbxListbox02.Value End Sub ' ...
- In der gemeinsamen Prozedur verhindert eine statische Variable das wiederholte Ausführen der Prozedur, während sie das erste Mal ausgeführt wird
Private Sub SelectEntry(ByVal strValue As String) Static blnBusy As Boolean If blnBusy = True Then Exit Sub ' hiermit wird verhindert, dass diese prozedur ein weiteres mal ausgeführt wird! blnBusy = True ' evt prüfen ob werte in listenfeldern vorhanden ist lbxListbox01.Value = strValue lbxListbox02.Value = strValue blnBusy = False End Sub
Da der Wert einer statischen Variable für jeden Durchlauf der Prozedur erhalten bleibt (in diesem Falle solange der Dialog existiert), kann mit deren Hilfe verhindert werden, dass die Prozedur mehr als einmal durchlaufen wird, sobald der erste Durchlauf gestartet wurde. Siehe auch Statische prozedurale Variable.