Flutter:如何使对象相互引用而不出现堆栈溢出错误?

0ejtzxu1  于 2022-11-30  发布在  Flutter
关注(0)|答案(1)|浏览(149)

我希望有一个简单的对象集,可以相互引用。有许多应用程序可以实现这一点(即:循环链接列表、多对多关系等)
我做了这个简单的例子来说明这个问题。
这是一个"people"对象,带有一个他们的朋友列表。然而,当我这样做的时候,这段代码的构建导致了堆栈溢出。这可能是因为bob调用了charlie(),而charlie调用了bob()。
我不认为会发生这种情况,因为anna、bob和charlie都应该只是对对象的引用。
如果你把bob从charlie的好友列表中删除,它就能正常工作,下面是测试它的样板代码。
例如:以people.dart为单位

class People {
      static Person anna = Person(name: "Anna", friends: [bob, charlie]);
      static Person bob = Person(name: "bob", friends: [charlie]);
      static Person charlie = Person(name: "charlie", friends: [bob]);
    
      static List<Person> everyone = [anna, bob, charlie];
    }
    
    class Person {
      String name;
      List<Person> friends;
      Person({required this.name, this.friends = const []});
    }

这里是锅炉板代码。对于main.dart

import 'package:flutter/material.dart';
    
    import 'people.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Friends test'),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      const MyHomePage({super.key, required this.title});
    
      final String title;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: Column(
              children: People.everyone
                  .map<Widget>((person) => PersonWidget(person: person))
                  .toList()),
        );
      }
    }
    
    class PersonWidget extends StatelessWidget {
      const PersonWidget({required this.person, super.key});
      final Person person;
    
      @override
      Widget build(BuildContext context) {
        String text = "${person.name}'s friends are: ";
        for (Person friend in person.friends) {
          text += "${friend.name}, ";
        }
    
        return Text(text);
      }
    }

当鲍勃不是查理的朋友:

一旦鲍勃成为查理的朋友

可怜的查理不可能有任何朋友:* 悲伤的脸 *
最后注意:以上只是一个例子。实际的产品代码有很多对象,定义了很多属性。类似于flutter颜色的定义。(即:我希望找到一种简单的方法来定义许多这样的对象。

g52tjvyc

g52tjvyc1#

我不认为会发生这种情况,因为anna、bob和charlie都应该只是对对象的引用。
static变量是延迟初始化的,所以当你访问bob时,Person(name: "bob", friends: [charlie])被执行。这访问charliecharlie类似地执行Person(name: "charlie", friends: [bob])
然而,我们还没有完成bob的初始化。bob还没有被赋值给一个对象的引用,因为我们还没有完成它对Person构造函数的调用。(而且,由于Dart是一种应用顺序语言,在这种语言中,参数在调用函数之前进行求值,我们甚至还没有进入Person构造函数。)因此,您将进入一个循环初始化循环。
您应该先建构annabobcharlie对象,然后将它们变更为指涉其他对象。
另一种方法是使用闭包来延迟生成朋友列表,这样annabobcharlie可以在需要引用其他对象之前被初始化。

class People {
  static Person anna = Person(name: "Anna", friends: () => [bob, charlie]);
  static Person bob = Person(name: "bob", friends: () => [charlie]);
  static Person charlie = Person(name: "charlie", friends: () => [bob]);

  static List<Person> everyone = [anna, bob, charlie];
}

typedef ComputeFriends = List<Person> Function();

class Person {
  String name;

  ComputeFriends? _computeFriends;

  List<Person> _friends = const [];

  List<Person> get friends {
    final computeFriends = _computeFriends;
    if (computeFriends != null) {
      _friends = computeFriends();
      _computeFriends = null;
    }
    return _friends;
  }

  Person({required this.name, ComputeFriends? friends})
      : _computeFriends = friends;
}

相关问题