Hallo,
ich habe gemerkt, dass Types beim einfügen in ein Array wohl kopiert werden. Warum ist das so? Kann ich das irgendwie ändern?
Beispielcode
LIMITFPS 10
TYPE TBar
text$ = ""
x = 0
y = 0
ENDTYPE
LOCAL a AS TBar
LOCAL b AS TBar
LOCAL c AS TBar
LOCAL d AS TBar
LOCAL list[] AS TBar
DIM list[4]
FOR i = 0 TO 3
list[i].x = RND(1000)
list[i].y = RND(1000)
NEXT
a.text$ = "A"
b.text$ = "B"
c.text$ = "C"
//d.text$ = "D"
//Direct try
list[3].text$ = "D"
x = 10
WHILE TRUE
y = 10
FOR i = 0 TO 3
PRINT "Text: " + list[i].text$ + " x: " + list[i].x + " y: " + list[i].y, x, y
INC y, 10
NEXT
SHOWSCREEN
KEYWAIT
WEND
Erwartet:
Gesetzte Variable text$ bei allen Types im Array. Das ist aber leider nicht so. Nur die eine Typeinstanz d, bei der klappt es. Wohl, weil die Types beim Array kopiert werden. :(
PS. Sollte man die Fragen eigentlich eher ins Englische Forum posten, wenn man dieser mächtig ist, oder doch dann hier?
ähem, was treibst du eigentlich da? Das programm macht genau das, was du ihm sagst. Du ordnest nur dem letzten Element aus list[] einen Text zu. Wozu sollen die Instanzen a, b, c, und von TBar gut sein?
Was siehst du denn jetzt als Fehler an?
Hallo,
aus den Types werden ja beim kompilieren Klassen. Von anderen Programmiersprachen kenn ich das so, das Klassen meistens als Referenz übergeben werden.
Wenn ich nun zum Beispiel die Variable a ändern würde, würde sich auch der Inhalt der Variable an der Stelle list[0] ändern. Das passiert aber bei GLBasic nicht. Gibt es in GLBasic vielleicht einen speziellen Referenzoperator dafür?
ich befürchte, du wirfst da etwas durcheinander. Deine Variablen a-d sind Variablen vom Typ TBar. list[] ist ein Array vom Typ TBar. Beide haben erst einmal gar nichts miteinander zu tun, nur daß sie den gleichen Datentyp haben.
Wenn du den text$ von einem Element der Liste ändern möchtest, dann tu das doch einfach, wie du es schon mit den anderen Werten für x und y getan hast
list[0].text$ = "text1"
list[1].text$ = "text2"
usw.
Warum meinst du, daß in deinem Beispiel a auf list[0] zeigt, b auf list[1] etc.?
Der unten stehende Code wäre das Gleiche in Java, vielleicht ist es dann verständlicher:
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main m = new Main();
m.test();
}
public void test() {
ArrayList<Bar> barArray = new ArrayList<Bar>();
Bar a = new Bar();
Bar b = new Bar();
barArray.add(a);
barArray.add(b);
for (int i = 0;i < 2; ++i) {
barArray.get(i).x = 10;
}
// Variable a wird direkt verändert
a.text = "A";
// Variable b innerhalb des Arrays verändert
barArray.get(1).text = "B";
for (int i = 0;i < 2; ++i) {
System.out.println(barArray.get(i).text + ": " + barArray.get(i).x);
}
}
class Bar {
public String text = "";
public int x = 0;
public int y = 0;
}
}
Ausgabe:
Quote
run:
Text: A x:10
Text: B x:10
BUILD SUCCESSFUL (total time: 0 seconds)
Variable a und b wurden korrekt manipuliert. Bei GLBasic wäre das $text bei a nicht gesetzt.
Jow, es wird mit DIMPUSH übergeben/kopiert, ist schon richtig.
Machen würde ich es aber so:
FOR i = 0 TO 3
LOCAL t AS TBar
t.x = RND(1000)
t.y = RND(1000)
DIMPUSH TBar[], t
NEXT
...da das Array ja ein offenes Array ist, somit brauchst dein DIM list[4] nicht.
Aha, ok, bin zwar nicht so wirklich firm in Java, aber ich denke, dass kann ich noch nachvollziehen.
Ich versuche mal, das gegenüberzustellen:
ArrayList<Bar> barArray = new ArrayList<Bar>();
entspricht in etwas
LOCAL list[] AS TBar
in GLBasic
Bar a = new Bar();
Bar b = new Bar();
wäre dann
LOCAL a AS Tbar
LOCAL b AS Tbar
barArray.add(a);
barArray.add(b);
zum hinzufügen von Elementen an das Array wäre in GLBasic
DIMPUSH list[], a
DIMPUSH list[], b
allerdings wären noch keine Inhalte zugeordnet. Sinnvollerweise würde man hier zunächst a und b Werte zuordnen und dann in das Array schreiben
for (int i = 0;i < 2; ++i) {
barArray.get(i).x = 10;
}
wäre dann
FOREACH l IN list[]
l.x = 10
NEXT
Der Knackpuntk wäre dann wohl folgende Zeile
a.text = "A";
So wie ich das verstanden habe, würde damit auch das entsprechende Element in der Liste geändert, weil a darauf zeigt. Richtig?
Das geht dann in GLBasic so nicht, hier müsstest du schon gezielt das entsprechende Element aus dem Array ansprechen
list[0].text$ = "A"
Ich vermute, in Java, wird lediglich ein Zeiger auf a in der Liste gesichert, sodaß eine Zuweisung a.text = "test" auch den gewünschten Effekt hat. In GLBasic wird jedoch der Inhalt von a komponentenweise nach list[0] kopiert, sodaß eine Änderung an a nicht automatisch den Inhalt von list[0] mit ändert.
Ich hoffe, das war jetzt einigermaßen verständlich :)
@Schranz0r
Das ist richtig, stimmt. Nur sollte man bedenken, dass das nächste Element bei einem Push erst berechnet werden muss. Wenn man die Anzahl kennt z.B. 128 - ist das je nach Verwaltungsalgorythmus um einiges schneller. So ist es zumindest in den meisten Sprachen, denke auch in C++.
@Quentin
QuoteIn GLBasic wird jedoch der Inhalt von a komponentenweise nach list[0] kopiert
Genau kopiert werden die Variablen an dieser Stelle bei GLBasic, leider. Nur vielleicht liesse sich das ja durch einen Referenzoperator steuern? Oder hat das einen bestimmten Grund, dass die Variablen kopiert werden?
Quotewäre dann
FOREACH l IN list[]
l.x = 10
NEXT
Das mit dem Foreach würde so aber oder so nicht klappen, weil die bei einem Foreach ja kopiert werden. Deswegen habe ich ja die normale For-Schleife genommen.
na zum ersten Punkt würde ich mal sagen "That's why it's Basic" :))
Zwar gibt es auch in etlichen Basic-Dialekten mittlweile Zeiger, aber wirklich Basic-like ist das nicht. Nee im Ernst, warum GLBasic so arbeitet, wie es es scheinbar tut, kann ich dir nicht sagen.
die FOREACH-Schleife wird sehr wohl so funktionieren, weil l hier auf das jeweilige Elemte aus list[] zeigt.
@Foo:
Wieso sollte das langsamer sein?
Gehst du bei C++ und Vectoren her und definierst die größe vor?
Für was wären dann blabla.push_back() gut? ;)
Ne mal im ernst, die Types sind hier schneller als in anderen mirbekannten Basicdialekten.
Quote from: Quentin on 2009-Oct-05
die FOREACH-Schleife wird sehr wohl so funktionieren, weil l hier auf das jeweilige Elemte aus list[] zeigt.
Eben, dafür ist es auch gemacht worden ;)
AAAALSO.
Wenn man mit FOREACH arbeitet, dann ist die FOREACH Variable ein Zeiger! Echter Zeiger.
Wenn man unbedingt das Kopieren beim Dimpush übergehen will, kann man's so machen:
LOCAL a[] AS foo
locain id% = LEN(a[])
REDIM a[ id% +1 ]
a[id].xy = Wert