Search code examples
stringdartstring-interpolation

How can I multiply two variables inside the string in dart?


"${element['price'] * element['step']} c"

always showing error

The operator '*' isn't defined for the type 'Object'.

The result must be multiplied two variables and convert to string.

What is wrong? I can not find any answer. Making as documentation says.

The element is

var element = {
  'title': 'Apple and more more thing',
  'category': 'Fruit',
  'description': 'Some data to describe',
  'price': 24.67,
  'bonus': '1% bonus',
  'group': 'Picnik',
  'step': 1.0
};

Solution

  • Dart is a static type safe language so before your code are even running, the code has been analyzed to be sure that there are no statically determined type issues.

    In your example your have defined the following variable:

    var element = {
      'title': 'Apple and more more thing',
      'category': 'Fruit',
      'description': 'Some data to describe',
      'price': 24.67,
      'bonus': '1% bonus',
      'group': 'Picnik',
      'step': 1.0
    };
    

    By using var your are telling Dart that it should automatically determine the type. This can also be done in this case. Dart will see that all the keys in the map are String so we can safely assume the key type to be String.

    Then it looks at the values and tries to find a type which are common for all values. Since we have both double and String as values the type must be Object since we cannot be more specific if we want a type which contain all values.

    So the type of the map will be determined to be: Map<String, Object>.

    When you are then using the [] operator on the map it will be defined to return Object from this map since this is the only thing we can be sure of.

    But this is a problem when you try to do:

    "${element['price'] * element['step']} c"
    

    Since we in the analyzer phase can see we are going to call the * operator on Object the analyzer will then stop your program with a type error since what your are trying to do is not seen as type safe.

    There are multiple ways to fix it which you can also see in other answers:

    Type cast

    You can tell Dart "hey, I know what I am doing" and force Dart to use a specific type with:

    "${(element['price'] as double) * (element['step'] as double)} c"
    

    Dynamic

    You can declare your map to contain dynamic as value:

    var element = <String, dynamic>{
      'title': 'Apple and more more thing',
      'category': 'Fruit',
      'description': 'Some data to describe',
      'price': 24.67,
      'bonus': '1% bonus',
      'group': 'Picnik',
      'step': 1.0
    };
    

    This will remove all type safety of values in the map and you can then do anything you want with the values coming from the map without worrying about type issues by the analyzer. But the types will then be checked on runtime which can make your application crash if you gets the type wrong (like the type cast).

    Class solution

    You should really not use Map like you are doing. Instead, create a class:

    void main() {
      var element = Element(
          title: 'Apple and more more thing',
          category: 'Fruit',
          description: 'Some data to describe',
          price: 24.67,
          bonus: '1% bonus',
          group: 'Picnik',
          step: 1.0);
    
      print("${element.price * element.step} c"); // 24.67 c
    }
    
    class Element {
      String title;
      String category;
      String description;
      double price;
      String bonus;
      String group;
      double step;
    
      Element(
          {this.title,
          this.category,
          this.description,
          this.price,
          this.bonus,
          this.group,
          this.step});
    }
    

    By doing so, you can ensure Dart know the type of each property and get type safety.