class Point { num x, y; Point(num x, num y) { this.x = x; this.y = y; } }
x
four times just to initialize the field. Sucks! Better to do this: class Point { num x, y; Point(this.x, this.y); }
this.
, the field with this name will be automatically initialized with the argument value. In our example, another small trick is used - if the body of the constructor is empty, you can use it ;
instead of {}
. class Point { num x, y; Point(this.x, this.y); Point.zero() : x = 0, y = 0; Point.polar(num theta, num radius) { x = Math.cos(theta) * radius; y = Math.sin(theta) * radius; } }
Point
has three constructors — a regular one and two named. Here's how to use them: var a = new Point(1, 2); var b = new Point.zero(); var c = new Point.polar(Math.PI, 4.0);
new
with named constructors, these are not ordinary static methods. class Symbol { final String name; static Map<String, Symbol> _cache; factory Symbol(String name) { if (_cache == null) { _cache = {}; } if (_cache.containsKey(name)) { return _cache[name]; } else { final symbol = new Symbol._internal(name); _cache[name] = symbol; return symbol; } } Symbol._internal(this.name); }
Symbol
class. A character is about the same as a string, but we want to ensure that at any given time there is only one character with the given name. This makes it possible to safely test symbols for equality, simply by making sure that they point to the same object.factory
. When it is called, a new object is not created ( this
missing from the factory constructor). Instead, we need to explicitly create and return an object. In this example, we first check if there is a character with the same name in the cache, and return it if there is one. var a = new Symbol('something'); var b = new Symbol('something');
new
somewhere in the code to call a static factory method. void sayGreeting(String salutation, String name) { final greeting = '$salutation $name'; print(greeting); }
window.on.click.add((event) { print('You clicked the window.'); })
add()
method as an event handler. Finally, for small functions consisting of a single expression, there is a simplified syntax: var items = [1, 2, 3, 4, 5]; var odd = items.filter((i) => i % 2 == 1); print(odd); // [1, 3, 5]
=>
) and the expression, create a function that takes this argument and returns the result of evaluating the expression.=>
to define class members. Of course, you can do it like this: class Rectangle { num width, height; bool contains(num x, num y) { return (x < width) && (y < height); } num area() { return width * height; } }
class Rectangle { num width, height; bool contains(num x, num y) => (x < width) && (y < height); num area() => width * height; }
object.someProperty
. In Dart, you can define methods that will look like a call to a class field, but still execute arbitrary code. As in other languages, such methods are called getters and setters: class Rectangle { num left, top, width, height; num get right() => left + width; set right(num value) => left = value - width; num get bottom() => top + height; set bottom(num value) => top = value - height; Rectangle(this.left, this.top, this.width, this.height); }
Rectangle
class with four “real” properties — left
, top
, width
, and height
and two logical properties in the form of getters and setters — right
and bottom
. When using the class, there is no visible difference between natural fields and getters and setters: var rect = new Rectangle(3, 4, 20, 15); print(rect.left); print(rect.bottom); rect.top = 6; rect.right = 12;
final
), you can write the setter required by the interface.final
keyword.Rectangle
class to always have a non-negative size: class Rectangle { num left, top; num _width, _height; num get width() => _width; set width(num value) { if (value < 0) throw 'Width cannot be negative.'; _width = value; } num get height() => _height; set height(num value) { if (value < 0) throw 'Height cannot be negative.'; _height = value; } num get right() => left + width; set right(num value) => left = value - width; num get bottom() => top + height; set bottom(num value) => top = value - height; Rectangle(this.left, this.top, this._width, this._height); }
num abs(num value) => value < 0 ? -value : value; final TWO_PI = Math.PI * 2.0; int get today() { final date = new DateTime.now(); return date.day; }
Math
. It is difficult to say that this is an ingrained habit from other languages, or a programming practice that is also useful for Dart. In this area, we really need feedback from other developers.main()
. When working with the DOM, the “variables” document
and window
are getters defined at the top level. 'I am a "string"' "I'm one too" '''I'm on multiple lines ''' """ As am I """
var name = 'Fred'; var salutation = 'Hi'; var greeting = salutation + ', ' + name;
var name = 'Fred'; var salutation = 'Hi'; var greeting = '$salutation, $name';
$
), followed by the variable name, the value of the variable will be substituted (if it is not a string, the toString()
method will be called). Expressions can be placed inside curly brackets: var r = 2; print('The area of a circle with radius $r is ${Math.PI * r * r}');
1 + 2
operator is just a syntactic sugar for calling a method. From the point of view of language, this example looks like 1.+(2)
.Vector
class: class Vector { num x, y; Vector(this.x, this.y); operator +(Vector other) => new Vector(x + other.x, y + other.y); }
var position = new Vector(3, 4); var velocity = new Vector(1, 2); var newPosition = position + velocity;
a + b
, the meaning of the operation depends on the type a
.==
and !=
And ===
and !==
. It looks familiar to JavaScript programmers, but here they work a little differently.==
and !=
serve to check for equivalence. 99% of the time you will use them. Unlike JavaScript, they do not make any implicit conversions, so they will behave more predictably. Do not be afraid to use them! Unlike Java, they work with any types for which an equivalence relation is defined. No more someString.equals("something")
.==
for your types, if that makes sense. There is no need to overload !=
, Dart will automatically output it from ==
.===
and !==
, is used to check for identity. a === b
returns true
only if a
and b
are the same object in memory. You rarely have to use them in practice. By default, ==
relies on ===
if the type does not define an equivalence relation, so ===
will be needed in a single case — to bypass the user-defined ==
.Source: https://habr.com/ru/post/130120/
All Articles