【问题标题】:How to manage Lists with Future in dart?如何在 dart 中使用 Future 管理列表?
【发布时间】:2014-05-26 16:02:50
【问题描述】:

我是 Dart 的新手;并且,我创建了一个名为 Deck 的扑克牌对象列表。我正在尝试选择一张随机卡片,然后从牌组中取出卡片。我得到了重复,因为似乎在减少牌组之前选择了后续卡。我将如何处理将来会从牌组中随机抽取 10 张独特牌的事件链?

class Card{
String face;
String suit;
String rank;
String imgSrc;
String holdImgSrc;

Card(
 this.face,
 this.suit,
 this.rank,
 this.imgSrc,
 this.holdImgSrc
 );
}
import 'dart:math' show Random;
Random indexGen = new Random();


getCard1(){
  card1 = deck[indexGen.nextInt(deck.length)];
  deck.removeWhere((item) => item == card1);
  return card1;  
}         

getCard2(){
  card2 = deck[indexGen.nextInt(deck.length)];
  deck.removeWhere((item) => item == card2);
  return card2;
}

当我尝试将卡片对象作为未来返回时,我得到:

new Future((getCard1()))
  .then((getCard2()))
  .then((getCard3()));

'Card' 类型不是 'computation' 的 '() => dynamic' 类型的子类型。

当我尝试返回牌组列表时,我得到:

类型“列表”不是“计算”类型“()=>动态”的子类型。

我是否缺少正确的语法、我的逻辑缺陷,或者我是否需要通过观察变化来以不同的方式处理列表?

编辑添加:期货语法有效,但是,删除似乎没有正确发生。 我将代码更改为下面 Jim-Y 建议的代码,除了使用第二个命名构造函数从 List 预加载新 Card 对象。修改后的代码和打印输出如下:

fullDeck[
...
var tenC  = new Card.full(17,'10_of_clubs','c','10','10_of_clubs.png','10_of_clubs_h.png');
var tenD  = new Card.full(18,'10_of_diamonds','d','10','10_of_diamonds.png','10_of_diamonds_h.png');
var tenS  = new Card.full(19,'10_of_spades','s','10','10_of_spades.png','10_of_spades_h.png');
var tenH  = new Card.full(20,'10_of_clubs','c','10','10_of_clubs.png','10_of_clubs_h.png');
...]

Deck<Card> deck = new Deck<Card>();
  Random indexGen = new Random();

   for(var c = 0; c < 20; ++c) {
     var card = new Card(c);
     deck.add(fullDeck[c]);//List of 52 full card objects

           }

   for(var i = 0; i < 10; ++i) {
     var rnd = indexGen.nextInt(deck.size());
     print('${deck.get(rnd).face} Deck size: ${deck.size()}');           
           }

         }

4_of_clubs Deck size: 19
10_of_diamonds Deck size: 18
5_of_clubs Deck size: 17
4_of_spades Deck size: 16
5_of_spades Deck size: 15
10_of_clubs Deck size: 14
10_of_clubs Deck size: 13
3_of_spades Deck size: 12
5_of_diamonds Deck size: 11
3_of_diamonds Deck size: 10

如您所见,Clubs 的 10 被打印了两次。那么,如果 10 在第 6 关中被删除了,为什么它在第 7 关中仍然存在?

【问题讨论】:

  • 你在getCardX()中使用的card1card2变量是什么
  • 它们是卡片对象。列表牌组中充满了卡片对象。
  • 您直接调用 getCard1,并使用返回的 Card 对象作为 new Future() 的参数。对于正确的类型,你需要写new Future(getCard1).then((_)=&gt;getCard2()).then((_)=&gt;getCard3())。它仍然不会记住被移除的卡片。
  • Irn:关于记住卡片,你是正确的。它们被声明为全局变量,但不会更新。未来还有更多的学习曲线:)

标签: dart dart-async


【解决方案1】:

如果您想以这种方式链接调用,则方法必须返回一个未来:

注意:我没有测试过代码:

// I don't see what type 'Card' actually is from your code
Future<Card> getCard1(){
  return new Future(() {
    card1 = deck[indexGen.nextInt(deck.length)];
    deck.removeWhere((item) => item == card1);
    return card1;  
  });
}  

getCard2() 也一样

Future<Card> getCard2(){
  return new Future(() {
    card2 = deck[indexGen.nextInt(deck.length)];
    deck.removeWhere((item) => item == card2);
    return card2;
  });
}

你用它来称呼它

getCard1().then((c) => getCard2()).then((c) => print(c));

因为getCard1getCard2 本质上是相同的方法,您可以将它们组合成一个

List<Card> cards = [];

Future<Card> getCard(int i){
  return new Future(() {
    cards[i] = deck[indexGen.nextInt(deck.length)]; // not clear what card is 
    deck.removeWhere((item) => item == card[i]);
    return card[i];  
  });
}  

getCard(1).then((c) => getCard(2)).then((c) => print(c));

【讨论】:

  • 感谢您的超级快速回复和澄清。添加了类声明;而且,修改方法让我摆脱了错误消息!
  • 卡是:卡card1;
  • 好的。在我尝试过的组合方法上:deck.removeWhere((item) => item == cards[i]);返回卡[i];并按照你的建议打电话。现在我得到空对象没有方法'then'。
  • 记得从getCard函数返回future。
  • 另外,您可以使用removeAt 移除卡:cards[i] = deck.removeAt(indexGen.nextInt(deck.length));。比在您已经知道索引时使用 removeWhere 更简单、更高效。
【解决方案2】:

我现在不明白为什么你需要为此使用 Futures。在下面的代码中,我将尝试使用 Dart 的通用特性解决从卡组中移除卡片的可能更好的方法:)

你原来的 Card 类,我为了演示而扩展了它:

class Card {
  int id;
  String face;
  String suit;
  String rank;
  String imgSrc;
  String holdImgSrc;

  Card(this.id);
  Card.full(this.id, this.face, this.suit, this.rank, this.imgSrc, this.holdImgSrc);
}

然后,您可以为您的卡片制作一个通用容器,而不是使用简单的列表。

class Deck<T extends Card> {
  List<T> _container = new List<T>();

  T get(int index) => _container.removeAt(index);
  void add(T item) => _container.add(item);
  int size() => _container.length;
}

这将使您的示例在以后更容易扩展,并且您可以通过它获得很多表达能力。

然后,你可以写这样的东西,从牌组中删除 10 个随机元素。

void main() {
  Deck<Card> deck = new Deck<Card>();
  Random indexGen = new Random();

  for(var c = 0; c < 20; ++c) {
    var card = new Card(c);
    deck.add(card);
  }

  for(var i = 0; i < 10; ++i) {
    var rnd = indexGen.nextInt(deck.size());
    print('${deck.get(rnd).id} Deck size: ${deck.size()}');
  }
}

在这个简单的例子中,这些简单的卡片对象没有重复。但是,如果需要,您可以使用 (n) fGet 方法扩展 Deck 类,这可能是 @Günter 之前提到的返回 Future 的方法。

我希望我给了你一些好主意:)

干杯

【讨论】:

  • 酷。所以我们转移到一个有 getter 和 setter 的类,但我不明白什么是可以防止偶尔生成相同的随机数。 Set 的交集呢?var deck = new Set();//所有 52 张卡片var myTenCards = new Set(); var listDeck = 新列表(52); while (myTenCards.length
  • 我同意期货似乎没有必要。并且为了避免两次获得同一张牌,我想说最简单,也许最真实的领域是洗牌,然后取前 10 张牌。也就是说,生成牌组的随机排列。有一个简单的算法(Knuth shuffle)。
  • 艾伦。对于洗牌,你的是最好的务实解决方案。我试图通过一次删除一个来模拟一个真实的套牌,这让我质疑为什么我的算法会因重复而失败,所以问题是学术上的,如何做到这一点。上面的 Set 方法也创建了重复项。谢谢
  • T get(int index) => _container.removeAt(index);是不是一次又一次地生成相同数字的关键,但不是您期望的方式。 removeAt 不仅会返回一个项目,还会从容器中删除该项目,Dart 将重新排列(左移索引)元素。所以在下一回合,rnd num 生成器会创建一个介于 [0-19) 之间的随机数。有很多可能不从列表中删除卡,只需将其设置为下一轮专用。
  • 明白了,谢谢。在最初,我假设重复的数字是为了异步操作比删除移动得更快。经过进一步检查,索引似乎在删除后没有按应有的方式更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 1970-01-01
  • 2021-04-28
相关资源
最近更新 更多