类型“_CompactLinkedHashSet<String>”不是类型 'Map<dynamic, dynamic>?' 的子类型
type '_CompactLinkedHashSet<String>' is not a subtype of type 'Map<dynamic, dynamic>?'
我正在关注 tutorial 使用 flutter 和 rethinkdb 构建消息传递应用程序。它尚未针对空安全性进行更新,但作为初学者,我正在努力前进并使用最新的软件包和最新版本的 flutter 学习它。
我正在尝试测试输入通知,但遇到无法破译的错误。
type '_CompactLinkedHashSet<String>' is not a subtype of type 'Map<dynamic, dynamic>?'
package:rethink_db_ns/src/ast.dart:1223
TypingNotification.send
package:chat/…/typing/typing_notification.dart:22
main.<fn>
test/typing_notification_test.dart:44
main.<fn>
test/typing_notification_test.dart:37
我拥有的所有地图都是 Map,所以我不确定 Map 来自哪里。我用的也是package:rethink_db_ns,而不是教程作者用的,是添加ns之前的rethink包。所以我不确定我是否必须为新包做进一步的改变。在尝试 运行 测试之前,我还确保没有看到任何红色波浪线。
这是我的文件:
这是我尝试 运行 测试并得到上述错误的测试文件:
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';
import 'package:chat/src/services/typing/typing_notification.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';
import 'helpers.dart';
void main() {
RethinkDb r = RethinkDb();
late Connection connection;
late TypingNotification sut;
setUp(() async {
connection = await r.connect();
await createDb(r, connection);
sut = TypingNotification(r, connection);
});
tearDown(() async {
sut.dispose();
await cleanDb(r, connection);
});
final user = User.fromJson({
'id': '1234',
'active': true,
'lastSeen': DateTime.now(),
});
final user2 = User.fromJson({
'id': '1111',
'active': true,
'lastSeen': DateTime.now(),
});
test('sent typing notification successfully', () async {
TypingEvent typingEvent = TypingEvent(
from: user2.id!,
to: user.id!,
event: Typing.start,
);
final res = await sut.send(event: typingEvent, to: user);
expect(res, true);
});
}
这里是typing_notification.dart
:
import 'dart:async';
import 'package:chat/src/models/user.dart';
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/services/typing/typing_notification_service_contract.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';
class TypingNotification implements ITypingNotification {
final Connection _connection;
final RethinkDb _r;
final _controller = StreamController<TypingEvent>.broadcast();
StreamSubscription? _changefeed; // added ? to this
TypingNotification(this._r, this._connection); //added this._change
@override
Future<bool> send({required TypingEvent event, required User to}) async {
if (!to.active) return false;
Map record = await _r
.table('typing_events')
.insert(event.toJson(), {'conflict:' 'update'}).run(_connection);
return record['inserted'] == 1;
}
@override
Stream<TypingEvent> subscribe(User user, List<String> userIds) {
_startReceivingTypingEvents(user, userIds);
return _controller.stream;
}
@override
void dispose() {
_changefeed?.cancel();
_controller.close();
}
_startReceivingTypingEvents(User user, List<String> userIds) {
_changefeed = _r
.table('typing_events')
.filter((event) {
return event('to')
.eq(user.id)
.and(_r.expr(userIds).contains(event('from')));
})
.changes({'include_initial': true})
.run(_connection)
.asStream()
.cast<Feed>()
.listen((event) {
event
.forEach((feedData) {
if (feedData['new_val'] == null) return;
final typing = _eventFromFeed(feedData);
_controller.sink.add(typing);
_removeEvent(typing);
})
.catchError((err) => print(err))
.onError((error, stackTrace) => print(error));
});
}
TypingEvent _eventFromFeed(feedData) {
return TypingEvent.fromJson(feedData['new_val']);
}
_removeEvent(TypingEvent event) {
_r
.table('typing_events')
.get(event.id)
.delete({'return_changes': false}).run(_connection);
}
}
这里是typing_event.dart
:
enum Typing { start, stop }
extension TypingParser on Typing {
String value() {
return toString().split('.').last;
}
static Typing fromString(String event) {
return Typing.values.firstWhere((element) => element.value() == event);
}
}
class TypingEvent {
final String from;
final String to;
final Typing event;
String? _id;
String? get id => _id;
TypingEvent({
required this.from,
required this.to,
required this.event,
});
Map<String, dynamic> toJson() => {
'from': this.from,
'to': this.to,
'event': this.event.value(),
};
factory TypingEvent.fromJson(Map<String, dynamic> json) {
var event = TypingEvent(
from: json['from'],
to: json['to'],
event: TypingParser.fromString(json['event']),
);
event._id = json['id'];
return event;
}
}
这里是 typing_notification_service_contract.dart
:
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';
abstract class ITypingNotification {
Future<bool> send(
{required TypingEvent event, required User to}); // the tutorial did not include ", required User to" but I added it to prevent an error, since required User to is passed in another file
Stream<TypingEvent> subscribe(User user, List<String> userIds);
void dispose();
}
最后,typing_event.dart
enum Typing { start, stop }
extension TypingParser on Typing {
String value() {
return toString().split('.').last;
}
static Typing fromString(String event) {
return Typing.values.firstWhere((element) => element.value() == event);
}
}
class TypingEvent {
final String from;
final String to;
final Typing event;
String? _id;
String? get id => _id;
TypingEvent({
required this.from,
required this.to,
required this.event,
});
Map<String, dynamic> toJson() => {
'from': this.from,
'to': this.to,
'event': this.event.value(),
};
factory TypingEvent.fromJson(Map<String, dynamic> json) {
var event = TypingEvent(
from: json['from'],
to: json['to'],
event: TypingParser.fromString(json['event']),
);
event._id = json['id'];
return event;
}
}
我是一个完全的初学者,并试图推动自己学习空安全,所以我的错误很可能很简单,我只是没有看到它。任何人都可以指出我正确的方向或在这里提供任何指导吗?如果您认为可能有帮助,我还可以根据要求添加更多详细信息。
尝试更换
.insert(event.toJson(), {'conflict:' 'update'}).run(_connection);
与
.insert(event.toJson(), {'conflict': 'update'}).run(_connection);
在第 22 行 typing_notification,.dart
中,它期待 Map,可能您打算将“:”放在字符串之外
我正在关注 tutorial 使用 flutter 和 rethinkdb 构建消息传递应用程序。它尚未针对空安全性进行更新,但作为初学者,我正在努力前进并使用最新的软件包和最新版本的 flutter 学习它。
我正在尝试测试输入通知,但遇到无法破译的错误。
type '_CompactLinkedHashSet<String>' is not a subtype of type 'Map<dynamic, dynamic>?'
package:rethink_db_ns/src/ast.dart:1223
TypingNotification.send
package:chat/…/typing/typing_notification.dart:22
main.<fn>
test/typing_notification_test.dart:44
main.<fn>
test/typing_notification_test.dart:37
我拥有的所有地图都是 Map
这是我的文件:
这是我尝试 运行 测试并得到上述错误的测试文件:
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';
import 'package:chat/src/services/typing/typing_notification.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';
import 'helpers.dart';
void main() {
RethinkDb r = RethinkDb();
late Connection connection;
late TypingNotification sut;
setUp(() async {
connection = await r.connect();
await createDb(r, connection);
sut = TypingNotification(r, connection);
});
tearDown(() async {
sut.dispose();
await cleanDb(r, connection);
});
final user = User.fromJson({
'id': '1234',
'active': true,
'lastSeen': DateTime.now(),
});
final user2 = User.fromJson({
'id': '1111',
'active': true,
'lastSeen': DateTime.now(),
});
test('sent typing notification successfully', () async {
TypingEvent typingEvent = TypingEvent(
from: user2.id!,
to: user.id!,
event: Typing.start,
);
final res = await sut.send(event: typingEvent, to: user);
expect(res, true);
});
}
这里是typing_notification.dart
:
import 'dart:async';
import 'package:chat/src/models/user.dart';
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/services/typing/typing_notification_service_contract.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';
class TypingNotification implements ITypingNotification {
final Connection _connection;
final RethinkDb _r;
final _controller = StreamController<TypingEvent>.broadcast();
StreamSubscription? _changefeed; // added ? to this
TypingNotification(this._r, this._connection); //added this._change
@override
Future<bool> send({required TypingEvent event, required User to}) async {
if (!to.active) return false;
Map record = await _r
.table('typing_events')
.insert(event.toJson(), {'conflict:' 'update'}).run(_connection);
return record['inserted'] == 1;
}
@override
Stream<TypingEvent> subscribe(User user, List<String> userIds) {
_startReceivingTypingEvents(user, userIds);
return _controller.stream;
}
@override
void dispose() {
_changefeed?.cancel();
_controller.close();
}
_startReceivingTypingEvents(User user, List<String> userIds) {
_changefeed = _r
.table('typing_events')
.filter((event) {
return event('to')
.eq(user.id)
.and(_r.expr(userIds).contains(event('from')));
})
.changes({'include_initial': true})
.run(_connection)
.asStream()
.cast<Feed>()
.listen((event) {
event
.forEach((feedData) {
if (feedData['new_val'] == null) return;
final typing = _eventFromFeed(feedData);
_controller.sink.add(typing);
_removeEvent(typing);
})
.catchError((err) => print(err))
.onError((error, stackTrace) => print(error));
});
}
TypingEvent _eventFromFeed(feedData) {
return TypingEvent.fromJson(feedData['new_val']);
}
_removeEvent(TypingEvent event) {
_r
.table('typing_events')
.get(event.id)
.delete({'return_changes': false}).run(_connection);
}
}
这里是typing_event.dart
:
enum Typing { start, stop }
extension TypingParser on Typing {
String value() {
return toString().split('.').last;
}
static Typing fromString(String event) {
return Typing.values.firstWhere((element) => element.value() == event);
}
}
class TypingEvent {
final String from;
final String to;
final Typing event;
String? _id;
String? get id => _id;
TypingEvent({
required this.from,
required this.to,
required this.event,
});
Map<String, dynamic> toJson() => {
'from': this.from,
'to': this.to,
'event': this.event.value(),
};
factory TypingEvent.fromJson(Map<String, dynamic> json) {
var event = TypingEvent(
from: json['from'],
to: json['to'],
event: TypingParser.fromString(json['event']),
);
event._id = json['id'];
return event;
}
}
这里是 typing_notification_service_contract.dart
:
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';
abstract class ITypingNotification {
Future<bool> send(
{required TypingEvent event, required User to}); // the tutorial did not include ", required User to" but I added it to prevent an error, since required User to is passed in another file
Stream<TypingEvent> subscribe(User user, List<String> userIds);
void dispose();
}
最后,typing_event.dart
enum Typing { start, stop }
extension TypingParser on Typing {
String value() {
return toString().split('.').last;
}
static Typing fromString(String event) {
return Typing.values.firstWhere((element) => element.value() == event);
}
}
class TypingEvent {
final String from;
final String to;
final Typing event;
String? _id;
String? get id => _id;
TypingEvent({
required this.from,
required this.to,
required this.event,
});
Map<String, dynamic> toJson() => {
'from': this.from,
'to': this.to,
'event': this.event.value(),
};
factory TypingEvent.fromJson(Map<String, dynamic> json) {
var event = TypingEvent(
from: json['from'],
to: json['to'],
event: TypingParser.fromString(json['event']),
);
event._id = json['id'];
return event;
}
}
我是一个完全的初学者,并试图推动自己学习空安全,所以我的错误很可能很简单,我只是没有看到它。任何人都可以指出我正确的方向或在这里提供任何指导吗?如果您认为可能有帮助,我还可以根据要求添加更多详细信息。
尝试更换
.insert(event.toJson(), {'conflict:' 'update'}).run(_connection);
与
.insert(event.toJson(), {'conflict': 'update'}).run(_connection);
在第 22 行 typing_notification,.dart
中,它期待 Map,可能您打算将“:”放在字符串之外