#flutter #dart
Вопрос:
Учитывая эти два простых шаблона проектирования для статических значений, каковы последствия каждого из них? Идентичны ли они по производительности и использованию памяти в приложениях Dart/Flutter при доступе к их участникам?
Пример А: MyStringsGetters
const strings = MyStringsGetters();
class MyStringsGetters {
const MyStringsGetters();
get helloWorld => 'Hello, World';
}
Пример B: MyStringsMembers
const strings = MyStringsMembers();
class MyStringsMembers {
const MyStringsMembers();
static const helloWorld = 'Hello, World';
}
Ответ №1:
Пример А будет более неэффективным. Геттеры-это, по сути, методы, которые вызываются во время выполнения, и их ответ не кэшируется. Да, экземпляр класса есть const
и будет сохранен в памяти только один раз, но получатель, по сути, будет создавать новый адрес памяти каждый раз, когда вы его вызываете.
Я бы предложил пойти с примером B.
Вот мое доказательство. Я создал фиктивное приложение, которое отображает 100 экземпляров текста, отображающих строку Hello World, используя оба примера, которыми вы поделились, и вот результаты:
Вы можете ясно видеть, что выделенная память намного меньше, Example B
и основная причина в том, что получатель выделит новые адреса памяти.
Вы также можете использовать инструмент разработки памяти для работы с такого рода вопросами. Вот код, который я использовал:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
const strings = MyStringsMembers();
class MyStringsMembers {
const MyStringsMembers();
static const helloWorld = 'Hello, World';
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: MyStringsMembers.helloWorld,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Widget> _widgets() {
List<Widget> result = [];
for (var i = 0; i < 10000; i ) {
result.add(Text(MyStringsMembers.helloWorld));
}
return resu<
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, children: _widgets()),
),
);
}
}
Я попытался просмотреть документацию и не смог найти много об этом. Самая близкая информация, которую я нашел в книге спецификаций языка программирования Dart, страница 37.
Геттеры-это функции (9), которые используются для извлечения значений свойств объекта.
Учитывая, что вы не сохраняете значение строки как свойство объекта, а геттер, по сути, является просто вспомогательной функцией, которая выполняет то, что вы указываете, в конечном итоге при каждом вызове будет выделяться память. "Hello world"
по сути, это означает создание новой строки в памяти с этим содержимым.
Комментарии:
1. Это была моя интуитивная мысль, и я согласен с вашими утверждениями/подходом. Я не смог найти никаких документов, подтверждающих утверждение: «Геттеры-это, по сути, методы, которые вызываются во время выполнения, и их ответ не кэшируется». У вас есть какая-либо письменная документация, подтверждающая это? Мне нравится читать об этом; в противном случае, отличный ответ!
2. Я приложил ответ к вашему комментарию в ответе. Короче говоря, я не смог найти много информации о геттерах, но я нашел некоторые доказательства, подтверждающие, что геттеры-это просто функции, которые можно использовать для извлечения значения различных объектов. Учитывая, что объект, который вы извлекаете с помощью вашего геттера, не является свойством объекта, и вы динамически выделяете строку, не сохраняя ее нигде, вы в конечном итоге создаете новые экземпляры каждый раз, когда вызывается функция.
3. Спасибо! Я очень ценю это.
Ответ №2:
Вроде. Пример A, геттер будет вызван для объекта MyStringsGetters. т. е. strings.helloWorld
Но пример B, HelloWorld будет вызываться на MyStringsMembers. т. Е. вы не можете вызывать strings.helloWorld
, как в примере A.
Вы должны использовать версию примера B, если одно и то же значение перенастроено из геттера в классе независимо от экземпляра (отсюда static
ключевое слово).
Но пример А может быть изменен на
void main(){
print(MyClass("Hello World").value);
print(MyClass("Thank you").value);
}
class MyClass {
final String _value;
const MyClass(String value) : _value=value;
String get value => _value;
}
Вы получите результат
Hello World
Thank you
MyClass по-прежнему является a const
, что означает, что все возможные значения MyClass будут известны как время компиляции.