Was sind die genauen Regeln, wenn Sie Klammern, Punkte, geschweifte Klammern, = (Funktionen) usw. weglassen können?


106

Was sind die genauen Regeln, wenn Sie Klammern, Punkte, geschweifte Klammern, = (Funktionen) usw. weglassen können?

Beispielsweise,

(service.findAllPresentations.get.first.votes.size) must be equalTo(2).
  • service ist mein Objekt
  • def findAllPresentations: Option[List[Presentation]]
  • votes kehrt zurück List[Vote]
  • muss und sein sind beide Funktionen von Spezifikationen

Warum kann ich nicht gehen:

(service findAllPresentations get first votes size) must be equalTo(2)

?

Der Compilerfehler ist:

"RestServicesSpecTest.this.service.findAllPresentations vom Typ Option [List [com.sharca.Presentation]] akzeptiert keine Parameter."

Warum denke ich, dass ich versuche, einen Parameter zu übergeben? Warum muss ich für jeden Methodenaufruf Punkte verwenden?

Warum muss gleich (service.findAllPresentations get first votes size)sein? (2) führt zu:

"nicht gefunden: Wert zuerst"

Das "muss gleich 2 sein" von (service.findAllPresentations.get.first.votes.size)muss gleich 2 sein, dh die Methodenverkettung funktioniert gut? - Objektkette Kette Kette Parameter

Ich habe das Scala-Buch und die Website durchgesehen und kann keine umfassende Erklärung finden.

Ist es tatsächlich so, wie Rob H in der Frage zum Stapelüberlauf erklärt ? Welche Zeichen kann ich in Scala weglassen? , dass der einzig gültige Anwendungsfall für das Weglassen des '.' ist für Operationen im Stil "Operand Operator Operand" und nicht für Methodenverkettung?

Antworten:


87

Sie scheinen über die Antwort gestolpert zu sein. Wie auch immer, ich werde versuchen, es klar zu machen.

Sie können Punkte weglassen, wenn Sie die Präfix-, Infix- und Postfix-Notationen verwenden - die sogenannte Operator-Notation . Während Sie die Operator-Notation verwenden, können Sie die Klammer nur dann weglassen, wenn weniger als zwei Parameter an die Methode übergeben werden.

Jetzt ist die Operator-Notation eine Notation für den Methodenaufruf , was bedeutet, dass sie nicht verwendet werden kann, wenn das aufgerufene Objekt nicht vorhanden ist.

Ich werde kurz auf die Notationen eingehen.

Präfix:

Nur ~, !, +und -kann in Präfixnotation verwendet werden. Dies ist die Notation, die Sie beim Schreiben von !flagoder verwenden val liability = -debt.

Infix:

In dieser Notation wird die Methode zwischen einem Objekt und seinen Parametern angezeigt. Hier passen alle arithmetischen Operatoren.

Postfix (auch Suffix):

Diese Notation wird verwendet, wenn die Methode einem Objekt folgt und keine Parameter empfängt . Zum Beispiel können Sie schreiben list tail, und das ist Postfix-Notation.

Sie können Infix-Notationsaufrufe problemlos verketten, solange keine Methode verwendet wird. Zum Beispiel möchte ich den folgenden Stil verwenden:

(list
 filter (...)
 map (...)
 mkString ", "
)

Das ist das Gleiche wie:

list filter (...) map (...) mkString ", "

Warum verwende ich hier Klammern, wenn Filter und Map einen einzigen Parameter annehmen? Das liegt daran, dass ich ihnen anonyme Funktionen übergebe. Ich kann anonyme Funktionsdefinitionen nicht mit Infix-Stil mischen, da ich eine Grenze für das Ende meiner anonymen Funktion benötige. Die Parameterdefinition der anonymen Funktion kann auch als letzter Parameter der Infix-Methode interpretiert werden.

Sie können Infix mit mehreren Parametern verwenden:

string substring (start, end) map (_ toInt) mkString ("<", ", ", ">")

Curry-Funktionen sind mit der Infix-Notation schwer zu verwenden. Die Faltfunktionen sind ein klares Beispiel dafür:

(0 /: list) ((cnt, string) => cnt + string.size)
(list foldLeft 0) ((cnt, string) => cnt + string.size)

Sie müssen Klammern außerhalb des Infix-Aufrufs verwenden. Ich bin mir nicht sicher, welche genauen Regeln hier gelten.

Lassen Sie uns nun über Postfix sprechen. Postfix kann schwierig zu verwenden sein, da es nur am Ende eines Ausdrucks verwendet werden kann . Sie können beispielsweise Folgendes nicht tun:

 list tail map (...)

Weil der Schwanz nicht am Ende des Ausdrucks erscheint. Das kannst du auch nicht:

 list tail length

Sie können die Infixnotation verwenden, indem Sie das Ende der Ausdrücke in Klammern markieren:

 (list tail) map (...)
 (list tail) length

Beachten Sie, dass von der Postfix-Notation abgeraten wird, da sie möglicherweise unsicher ist .

Ich hoffe, das hat alle Zweifel ausgeräumt. Wenn nicht, schreibe einfach einen Kommentar und ich werde sehen, was ich tun kann, um ihn zu verbessern.


ahh, du sagst also, dass in meiner Aussage: (((((realService findAllPresentations) get) first) Stimmen) size) gleich 2 sein muss - get, first, Stimmen und Größe sind alle Postfix-Operatoren, da sie keine Parameter annehmen ? Also frage ich mich, was sein muss und was gleich ist ...
Antony Stubbs

Ich sage nichts dergleichen, obwohl ich mir ziemlich sicher bin, dass dies der Fall sein muss. :-) "be" ist wahrscheinlich ein Hilfsobjekt, um die Syntax schöner zu machen. Oder genauer gesagt, um die Verwendung der Infix-Notation mit "must" zu ermöglichen.
Daniel C. Sobral

Gut bekommen ist Option.get, Zuerst ist list.first, Stimmen ist eine Fallklasseneigenschaft und Größe ist list.size. Was denkst du jetzt?
Antony Stubbs

Ah ja - dies alles wird durch die Tatsache verstärkt, dass "(realService findPresentation 1) .get.id muss gleich 1 sein" funktioniert - da Service # findPresentations (id: Int) anscheinend ein Infix-Operator ist. Cool - ich denke ich verstehe es jetzt. :)
Antony Stubbs

42

Klassendefinitionen:

valoder varkann in Klassenparametern weggelassen werden, wodurch der Parameter privat wird.

Durch Hinzufügen von var oder val wird es öffentlich (dh es werden Methodenzugriffsmethoden und Mutatoren generiert).

{} kann weggelassen werden, wenn die Klasse keinen Körper hat, d. h.

class EmptyClass

Klasseninstanziierung:

Generische Parameter können weggelassen werden, wenn sie vom Compiler abgeleitet werden können. Beachten Sie jedoch, dass der Typparameter immer abgeleitet wird, wenn Ihre Typen nicht übereinstimmen. Ohne Angabe des Typs erhalten Sie möglicherweise nicht das, was Sie erwarten - das heißt, gegeben

class D[T](val x:T, val y:T);

Dies gibt Ihnen einen Typfehler (Int gefunden, erwartete Zeichenfolge)

var zz = new D[String]("Hi1", 1) // type error

Während dies gut funktioniert:

var z = new D("Hi1", 1)
== D{def x: Any; def y: Any}

Weil der Typparameter T als der am wenigsten verbreitete Supertyp der beiden abgeleitet wird - Any.


Funktionsdefinitionen:

= kann gelöscht werden, wenn die Funktion Unit (nichts) zurückgibt.

{}Denn der Funktionskörper kann gelöscht werden, wenn die Funktion eine einzelne Anweisung ist, aber nur, wenn die Anweisung einen Wert zurückgibt (Sie benötigen das =Vorzeichen), d. h.

def returnAString = "Hi!"

aber das funktioniert nicht:

def returnAString "Hi!" // Compile error - '=' expected but string literal found."

Der Rückgabetyp der Funktion kann weggelassen werden, wenn er abgeleitet werden kann (für eine rekursive Methode muss der Rückgabetyp angegeben werden).

() kann gelöscht werden, wenn die Funktion keine Argumente akzeptiert, d. h.

def endOfString {
  return "myDog".substring(2,1)
}

was konventionell Methoden vorbehalten ist, die keine Nebenwirkungen haben - dazu später mehr.

()wird bei der Definition eines Pass-by-Name- Parameters nicht per se gelöscht , aber es handelt sich tatsächlich um eine ganz semantisch andere Notation, d. h.

def myOp(passByNameString: => String)

MyOp verwendet einen Parameter für die Namensübergabe, der im Gegensatz zu Funktionsparametern zu einem String führt (dh es kann sich um einen Codeblock handeln, der einen String zurückgibt).

def myOp(functionParam: () => String)

Das heißt, myOpnimmt eine Funktion, die keine Parameter hat, und gibt einen String zurück.

(Wohlgemerkt, Pass-by-Name-Parameter werden in Funktionen kompiliert; dies macht die Syntax nur schöner.)

() kann in der Funktionsparameterdefinition gelöscht werden, wenn die Funktion nur ein Argument akzeptiert, zum Beispiel:

def myOp2(passByNameString:(Int) => String) { .. } // - You can drop the ()
def myOp2(passByNameString:Int => String) { .. }

Wenn jedoch mehr als ein Argument erforderlich ist, müssen Sie das () einschließen:

def myOp2(passByNameString:(Int, String) => String) { .. }

Aussagen:

.kann gelöscht werden, um die Operator-Notation zu verwenden, die nur für Infix-Operatoren (Operatoren von Methoden, die Argumente annehmen) verwendet werden kann. Weitere Informationen finden Sie in Daniels Antwort .

  • . kann auch für die Liste der Postfix-Funktionen gelöscht werden

  • () kann für Postfix-Operatoren list.tail gelöscht werden

  • () kann nicht mit folgenden Methoden verwendet werden:

    def aMethod = "hi!" // Missing () on method definition
    aMethod // Works
    aMethod() // Compile error when calling method
    

Da diese Notation gemäß der Konvention für Methoden reserviert ist, die keine Nebenwirkungen haben, wie z. B. List # tail (dh der Aufruf einer Funktion ohne Nebenwirkungen bedeutet, dass die Funktion außer ihrem Rückgabewert keine beobachtbaren Auswirkungen hat).

  • () kann für die Operatornotation gelöscht werden, wenn ein einzelnes Argument übergeben wird

  • () Möglicherweise müssen Postfix-Operatoren verwendet werden, die nicht am Ende einer Anweisung stehen

  • () Möglicherweise müssen verschachtelte Anweisungen, Enden anonymer Funktionen oder Operatoren angegeben werden, die mehr als einen Parameter verwenden

Wenn Sie eine Funktion aufrufen, die eine Funktion übernimmt, können Sie das () in der inneren Funktionsdefinition nicht weglassen, zum Beispiel:

def myOp3(paramFunc0:() => String) {
    println(paramFunc0)
}
myOp3(() => "myop3") // Works
myOp3(=> "myop3") // Doesn't work

Wenn Sie eine Funktion aufrufen, die einen By-Name-Parameter verwendet, können Sie das Argument nicht als parameterlose anonyme Funktion angeben. Zum Beispiel gegeben:

def myOp2(passByNameString:Int => String) {
  println(passByNameString)
}

Sie müssen es nennen als:

myOp("myop3")

oder

myOp({
  val source = sourceProvider.source
  val p = myObject.findNameFromSource(source)
  p
})

aber nicht:

myOp(() => "myop3") // Doesn't work

IMO kann eine übermäßige Verwendung von Drop-Return-Typen schädlich für die Wiederverwendung von Code sein. Schauen Sie sich einfach die Spezifikation an, um ein gutes Beispiel für eine eingeschränkte Lesbarkeit zu finden, da der Code keine expliziten Informationen enthält. Die Anzahl der Indirektionsebenen, um tatsächlich herauszufinden, um welchen Typ es sich bei einer Variablen handelt, kann verrückt sein. Hoffentlich können bessere Tools dieses Problem abwenden und unseren Code präzise halten.

(OK, um eine vollständigere, präzisere Antwort zu erstellen (wenn ich etwas verpasst habe oder etwas falsch / ungenau gemacht habe, bitte kommentieren Sie), habe ich am Anfang der Antwort hinzugefügt. Bitte beachten Sie, dass dies keine Sprache ist Spezifikation, also versuche ich nicht, es genau akademisch korrekt zu machen - nur eher wie eine Referenzkarte.)


10
Ich weine. Was ist das.
Profpatsch

12

Eine Sammlung von Zitaten, die Einblick in die verschiedenen Bedingungen geben ...

Persönlich dachte ich, dass die Spezifikation mehr enthalten würde. Ich bin mir sicher, dass es das geben muss, ich suche einfach nicht nach den richtigen Worten ...

Es gibt jedoch einige Quellen, und ich habe sie zusammengestellt, aber nichts wirklich Vollständiges / Umfassendes / Verständliches / Das erklärt mir die oben genannten Probleme ...:

"Wenn ein Methodenkörper mehr als einen Ausdruck hat, müssen Sie ihn mit geschweiften Klammern {…} umgeben. Sie können die Klammern weglassen, wenn der Methodenkörper nur einen Ausdruck hat."

Ab Kapitel 2, "Weniger tippen, mehr tun", von Programmier-Scala :

"Der Hauptteil der oberen Methode steht nach dem Gleichheitszeichen '='. Warum ein Gleichheitszeichen? Warum nicht einfach geschweifte Klammern {…} wie in Java? Weil Semikolons, Funktionstypen, Methodenargumentlisten und sogar geschweifte Klammern werden manchmal weggelassen, die Verwendung eines Gleichheitszeichens verhindert mehrere mögliche Parsing-Mehrdeutigkeiten. Die Verwendung eines Gleichheitszeichens erinnert uns auch daran, dass sogar Funktionen Werte in Scala sind, was mit Scalas Unterstützung der funktionalen Programmierung übereinstimmt, die ausführlicher in Kapitel 8, Funktionale Programmierung in beschrieben wird Scala. "

Aus Kapitel 1, "Null bis Sechzig: Einführung in Scala", von Programming Scala :

"Eine Funktion ohne Parameter kann ohne Klammern deklariert werden. In diesem Fall muss sie ohne Klammern aufgerufen werden. Dies unterstützt das Prinzip des einheitlichen Zugriffs, sodass der Aufrufer nicht weiß, ob das Symbol eine Variable oder eine Funktion mit Nein ist Parameter.

Dem Funktionskörper wird "=" vorangestellt, wenn er einen Wert zurückgibt (dh der Rückgabetyp ist etwas anderes als Unit), aber der Rückgabetyp und das "=" können weggelassen werden, wenn der Typ Unit ist (dh es sieht aus wie eine Prozedur im Gegensatz zu einer Funktion).

Zahnspangen um den Körper sind nicht erforderlich (wenn der Körper ein einzelner Ausdruck ist); Genauer gesagt ist der Körper einer Funktion nur ein Ausdruck, und jeder Ausdruck mit mehreren Teilen muss in geschweiften Klammern stehen (ein Ausdruck mit einem Teil kann optional in geschweiften Klammern eingeschlossen sein). "

"Funktionen mit null oder einem Argument können ohne Punkt und Klammern aufgerufen werden. Jeder Ausdruck kann jedoch mit Klammern versehen sein, sodass Sie den Punkt weglassen und trotzdem Klammern verwenden können.

Und da Sie Klammern überall dort verwenden können, wo Sie Klammern verwenden können, können Sie den Punkt weglassen und Klammern einfügen, die mehrere Anweisungen enthalten können.

Funktionen ohne Argumente können ohne Klammern aufgerufen werden. Beispielsweise kann die Funktion length () für String als "abc" .length und nicht als "abc" .length () aufgerufen werden. Wenn die Funktion eine ohne Klammern definierte Scala-Funktion ist, muss die Funktion ohne Klammern aufgerufen werden.

Konventionell werden Funktionen ohne Argumente, die Nebenwirkungen haben, wie z. B. println, in Klammern aufgerufen. diejenigen ohne Nebenwirkungen werden ohne Klammern genannt. "

Aus dem Blog-Beitrag Scala Syntax Primer :

"Eine Prozedurdefinition ist eine Funktionsdefinition, bei der der Ergebnistyp und das Gleichheitszeichen weggelassen werden. Ihr definierender Ausdruck muss ein Block sein. ZB ist def f (ps) {stats} äquivalent zu def f (ps): Unit = {stats }.

Beispiel 4.6.3 Hier ist eine Deklaration und eine Definition einer Prozedur mit dem Namen write:

trait Writer {
    def write(str: String)
}
object Terminal extends Writer {
    def write(str: String) { System.out.println(str) }
}

Der obige Code wird implizit mit dem folgenden Code vervollständigt:

trait Writer {
    def write(str: String): Unit
}
object Terminal extends Writer {
    def write(str: String): Unit = { System.out.println(str) }
}"

Aus der Sprachspezifikation:

"Mit Methoden, die nur einen einzigen Parameter annehmen, ermöglicht Scala dem Entwickler, das. Durch ein Leerzeichen zu ersetzen und die Klammern wegzulassen, wodurch die in unserem Beispiel für Einfügeoperatoren gezeigte Operatorsyntax aktiviert wird. Diese Syntax wird an anderen Stellen in der Scala-API verwendet, z als Konstruktionsbereichsinstanzen:

val firstTen:Range = 0 to 9

Auch hier ist to (Int) eine Vanilla-Methode, die innerhalb einer Klasse deklariert ist (hier gibt es tatsächlich einige implizitere Typkonvertierungen, aber Sie erhalten die Drift). "

Von Scala für Java-Flüchtlinge Teil 6: Über Java hinwegkommen :

"Wenn Sie nun" m 0 "versuchen, verwirft Scala, dass es sich um einen unären Operator handelt, da er nicht gültig ist (~,!, - und +). Es stellt fest, dass" m "ein gültiges Objekt ist - Es ist eine Funktion, keine Methode, und alle Funktionen sind Objekte.

Da "0" keine gültige Scala-Kennung ist, kann es sich weder um einen Infix- noch um einen Postfix-Operator handeln. Daher beschwert sich Scala, dass es ";" - was zwei (fast) gültige Ausdrücke trennen würde: "m" und "0". Wenn Sie es einfügen, wird es sich beschweren, dass m entweder ein Argument oder, falls dies nicht der Fall ist, ein "_" erfordert, um es in eine teilweise angewendete Funktion umzuwandeln. "

"Ich glaube, der Operator-Syntaxstil funktioniert nur, wenn Sie auf der linken Seite ein explizites Objekt haben. Mit der Syntax können Sie Operationen im Stil" Operand-Operator-Operand "auf natürliche Weise ausdrücken."

Welche Zeichen kann ich in Scala weglassen?

Was mich aber auch verwirrt, ist dieses Zitat:

"Es muss ein Objekt vorhanden sein, um einen Methodenaufruf zu erhalten. Beispielsweise können Sie" println "Hello World!" Nicht ausführen, da der println einen Objektempfänger benötigt. Sie können "Konsolendruck" in "Hallo Welt!" Ausführen, "was die Anforderungen erfüllt."

Denn soweit ich sehen kann, gibt es ein Objekt, um den Anruf entgegenzunehmen ...


1
Ok, also habe versucht, die Specs-Quelle zu lesen, um ein paar Hinweise und Woah zu bekommen. Das ist ein großartiges Beispiel für die Probleme mit magischem Code - zu viele Mixins, Typinferenz und implizite Konvertierungen und implizite Parameter. Es ist so schwer von außen nach innen zu verstehen! Für große Bibliotheken wie diese könnte ein besseres Werkzeug einige Wunder bewirken ... eines Tages ...
Antony Stubbs

3

Ich finde es einfacher, dieser Faustregel zu folgen: In Ausdrücken wechseln Leerzeichen zwischen Methoden und Parametern. In Ihrem Beispiel wird (service.findAllPresentations.get.first.votes.size) must be equalTo(2)als analysiert (service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2)). Beachten Sie, dass die Klammern um die 2 eine höhere Assoziativität haben als die Leerzeichen. Punkte haben auch eine höhere Assoziativität, (service.findAllPresentations.get.first.votes.size) must be.equalTo(2)würden also als analysieren (service.findAllPresentations.get.first.votes.size).must(be.equalTo(2)).

service findAllPresentations get first votes size must be equalTo 2analysiert als service.findAllPresentations(get).first(votes).size(must).be(equalTo).2.


2

In der zweiten Lesung ist dies vielleicht der Schlüssel:

Mit Methoden, die nur einen einzigen Parameter annehmen, ermöglicht Scala dem Entwickler, den zu ersetzen. mit einem Leerzeichen und lassen Sie die Klammern weg

Wie im Blogbeitrag erwähnt: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .

Vielleicht ist dies tatsächlich ein sehr strenger "Syntaxzucker", der nur funktioniert, wenn Sie effektiv eine Methode für ein Objekt aufrufen, das einen Parameter akzeptiert . z.B

1 + 2
1.+(2)

Und sonst nichts.

Dies würde meine Beispiele in der Frage erklären.

Aber wie gesagt, wenn jemand darauf hinweisen könnte, wo genau in der Sprachspezifikation dies angegeben ist, wäre er sehr dankbar.

Ok, ein netter Kerl (paulp_ von #scala) hat darauf hingewiesen, wo in der Sprachspezifikation diese Informationen sind:

6.12.3: Vorrang und Assoziativität von Operatoren bestimmen die Gruppierung von Teilen eines Ausdrucks wie folgt.

  • Wenn ein Ausdruck mehrere Infix-Operationen enthält, binden Operatoren mit höherer Priorität enger als Operatoren mit niedrigerer Priorität.
  • Bei aufeinanderfolgenden Infix-Operationen e0 op1 e1 op2. . .opn en mit Operatoren op1 ,. . . Wenn alle diese Operatoren dieselbe Priorität haben, müssen sie dieselbe Assoziativität haben. Wenn alle Operatoren linksassoziativ sind, wird die Sequenz als (... (e0 op1 e1) op2 ...) opn en interpretiert. Andernfalls wird die Sequenz als e0 op1 (e1 op2 (... .opn en) ...) Interpretiert, wenn alle Operatoren rechtsassoziativ sind.
  • Postfix-Operatoren haben immer eine niedrigere Priorität als Infix-Operatoren. ZB ist e1 op1 e2 op2 immer äquivalent zu (e1 op1 e2) op2.

Der rechte Operand eines linksassoziativen Operators kann aus mehreren in Klammern eingeschlossenen Argumenten bestehen, z. B. e op (e1, ..., en). Dieser Ausdruck wird dann als e.op (e1, ..., en) interpretiert.

Eine linksassoziative Binäroperation e1 op e2 wird als e1.op (e2) interpretiert. Wenn op rechtsassoziativ ist, wird dieselbe Operation als {val x = e1; e2.op (x)}, wobei x ein neuer Name ist.

Hmm - für mich passt es nicht zu dem, was ich sehe oder ich verstehe es einfach nicht;)


hmm, um die Verwirrung noch weiter zu verstärken, gilt dies auch: (((((realService findAllPresentations) get) first) Stimmen) Größe) muss gleich 2 sein, aber nicht, wenn ich eines dieser Klammerpaare entferne ...
Antony Stubbs

2

Es gibt keine. Sie werden wahrscheinlich beraten, ob die Funktion Nebenwirkungen hat oder nicht. Das ist Schwindel. Die Korrektur besteht darin, keine Nebenwirkungen in dem von Scala zulässigen angemessenen Umfang zu verwenden. Soweit dies nicht möglich ist, sind alle Wetten ungültig. Alle Wetten. Die Verwendung von Klammern ist ein Element der Menge "all" und überflüssig. Sobald alle Wetten geschlossen sind, wird kein Wert mehr angezeigt.

Dieser Rat ist im Wesentlichen ein Versuch eines fehlgeschlagenen Effektsystems (nicht zu verwechseln mit: ist weniger nützlich als andere Effektsysteme).

Versuchen Sie, keine Nebenwirkungen zu verursachen. Akzeptieren Sie danach, dass alle Wetten geschlossen sind. Das Verstecken hinter einer de facto syntaktischen Notation für ein Effektsystem kann und tut nur Schaden anrichten.


Nun, aber das ist das Problem, wenn Sie mit einer hybriden OO / Funktionssprache arbeiten, oder? In jedem praktischen Beispiel möchten Sie Nebenwirkungsfunktionen haben ... Können Sie uns auf einige Informationen zu "Effektsystemen" verweisen? Ich denke, das genauere Zitat ist das "Eine Funktion ohne Parameter kann ohne Klammern deklariert werden. In diesem Fall muss sie ohne Klammern aufgerufen werden. Dies bietet Unterstützung für das Prinzip des einheitlichen Zugriffs, sodass der Aufrufer nicht weiß, ob die Symbol ist eine Variable oder eine Funktion ohne Parameter. "
Antony Stubbs
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.