1. Use the operator keyword

Dart supports overloading operators. Here’s a quick example of how to use the operator keyword. When we say jet is younger than dragon, we usually mean age. Override > in the following Person object to compare the current size of Person with that of another Person. This has the advantage of being semantically clearer and more intuitive to read.

main() {
  Person toly = Person('jet'.26);
  Person ls = Person('the dragon less'.25);
  print(toly > ls); // true
}

class Person {
  String name;
  int age;

  Person(this.name, this.age);
  bool operator >(Person other) => this.age > other.age;
}
Copy the code

You can also compare the ages of two people by defining an LG method in the Person class below. But toly > ls looks a lot more natural than toly.lg(ls).

main() {
  Person toly = Person('jet'.26);
  Person ls = Person('the dragon less'.25);
  print(toly > ls); // true
  print(toly.lg(ls)); // true 
}

class Person {
  String name;
  int age;

  Person(this.name, this.age);
	// > Operator overload
  bool operator >(Person other) => this.age > other.age;
	// Use the method to compare the size
  bool lg(Person other) => this.age > other.age;
}
Copy the code

However, the use of > overload flexibility than the use of methods, the operator can only be a new, but the method can be defined at will. So if you want an operator-related behavior to look more natural for an object, consider using operator overloading.


2. Operator overload note points

Operator overloading simply simplifies writing and readability, and there are no hard and fast rules about it. Using the | operator, for example, to the person with higher return. Others may be confused when they look at your code, so it’s best to comment on special operator overloads.

main() {
  Person toly = Person('jet'.26.180);
  Person ls = Person('the dragon less'.25.179);

  Person taller = ls | toly;
  print(taller.name); / / jet
}

class Person {
  String name;
  int age;
  int height;

  Person(this.name, this.age, this.height);
  bool operator >(Person other) => this.age > other.age;
  // Return the taller person
  Person operator |(Person other) => this.height > other.height ? this : other;
}

Copy the code

So unwittingly also can produce very interesting effects, such as wy ls | | toly, can obtain the tallest.

main() {
  Person toly = Person('jet'.26.180);
  Person ls = Person('the dragon less'.25.179);
  Person wy = Person('WuYing'.25.179);
  print(toly > ls); // true

  Person taller = wy | ls | toly;
  print(taller.name); / / jet
}
Copy the code

3. Category of operator overloading

Not all operators in Dart can be overloaded, and not all operators are overloaded in the same format. Different operator overloads have different return values and entries. The following is my classification by return value and input parameter. Operator overloading of the same color in the figure is syntactically the same, but semantically different. That is, their usage is essentially the same, but in principle they are used semantically.


Single-parameter Boolean return value

The first row of >, <, >=, <=, == requires an object that returns bool.

bool operator= = (Object other) {
  return other is Person &&
      other.name == name &&
      other.height == height &&
      other.age == age;
}
Copy the code

Still, remember that the == symbol is just an identifier, and there is no logical problem with using >= to determine if two persons are equal. But in reality may be played, operator overloading should first respect semantics, semantics unknown operator overloading, better not use.

bool operator> = (Object other) {
  return other is Person &&
      other.name == name &&
      other.height == height &&
      other.age == age;
}
Copy the code

No parameter has a return value

The ~ operator takes no arguments and can return an object of any type. For example, the following is a ~ overload, return another property of the same Person object, implement the object copy. When you already have the toly object, just use ~toly to copy the object.

main() {
  Person toly = Person('jet'.26.180);
  print(~toly); // Person{name: name, age: 26, height: 180}
  print(identical(~toly,toly)); // false
}

  // The ~ operator is overloaded
  Person operator ~() => Person(
    this.name,
    this.age,
    this.height
  );
Copy the code

One parameter has a return value

The yellow operator overloads all require an input parameter that returns an object. Note that the parameter and return value are of arbitrary type. Get the i-th character of the name as follows with []. If the boundary is crossed, the last word is taken. Words with index bit 3 of the name can be obtained by toly[3]. It’s convenient to throw it away, but it’s not very good semantically, so this is just a demonstration.

Person toly = Person('Zhang Feng Jiatelei'.26.180);
print(toly[3]); / /,

// Operator overload
String operator[] (int index) {
  if (index >= name.length) return name[name.length - 1];
  return this.name[index];
}
Copy the code

There is no return value for both parameters

The only operator that can be overridden without a return value is []=, which is used to modify attributes inside a class. As follows, change the i-th character in the name with []=. In this way, it is much easier to modify a character and avoid repeating some of the processing logic.

Person toly = Person('Zhang Feng Jiatelei'.26.180);
toly[2] ="Jay";
print(toly); // Person{name: name, age: 26, height: 180}

// Operator overload
void operator[] = (int index,String char) {
  if (index >= name.length){
   name = name.substring(0,name.length- 1)+char;
  }else{
    String tail = name.substring(index+1);
    String front = name.substring(0,index); name = front+char+tail; }}Copy the code

To give you a better idea of the arbitrariness of operator overloading, here’s another small example. Lx [wy] = true; lx[wy] = true; lx[wy] = true; Then you can do it. Just as an example, operator overloading is not fixed and monotonous, and can be DIY for different scenarios, where complex logic and exception throwing can be handled. But don’t forget to add a comment or others won’t understand it.

main() {
  Person lx = Person("Lin xi", Gender.male);
  Person wy = Person("WuYing", Gender.female);
  
  lx[wy] = true; // Two people get married
  print(wy); // Person{name: name, gender: gender. Female, spouse: forest}
  
  wy[lx] = false;// They divorced
  print(wy); // Person{name: female, gender: gender. Female, spouse: null}
}

enum Gender { male, female }

class Person {
  String name;
  Gender gender;
  Person _spouse;

  Person(this.name, this.gender);

  // Are you single
  bool get single => _spouse == null;
	
  // Get married or divorced with the other.
  // lx[wy] = true; Two people get married
  // lx[wy] = false; Two married people get divorced
  void operator []=(Person other, bool flag) {
    if (this.gender == other.gender)
      throw Exception("same gender can't spouse!");

    bool spoused = identical(this._spouse, other);

    // If you are married and flag is false, you are divorced
    if(spoused && ! flag) { other._spouse =null;
      this._spouse = null;
      return;
    }

    // If both are single and flag is true, the two are married
    if (this.single && other.single && flag) {
      this._spouse = other;
      other._spouse = this;
      return;
    }
    throw Exception("hi, $name ,you can't spouse or divorce any more!");
  }

  @override
  String toString() {
    return 'Person{name: $name, gender: $gender, spouse: ${_spouse? .name}} '; }}Copy the code

4. Operator overloading in source code

While some might think that Dart operator overloading is rare, you actually use it all the time and don’t know it. For example, List objects can use the [] and []= operators, thanks to internal operator overloading.

List<int> arr = [0.1.2.3];
arr[0] =100;
print(arr[0]); / / 100
Copy the code


The Size object can + Offset to generate new dimensions, also because of the overridden operator.

Size size = Size(100.200);
Offset offset = Offset(100.300);
Size s3=  size + offset;
Copy the code

There are a lot of places in the source code that use operator overloading, so we can use these objects more conveniently and semantically. Operator overloading is a nice feature of Dart, but don’t mess with it. Respect the semantics. Well, that’s all for this piece. Thanks for watching