它们似乎都可以在相同的情况下使用。类型检查方面是否有不同的表示或不同的细微差别?
已编辑以更新空安全性(使用Object?
代替Object
)。
dynamic
的另一个视角是,它实际上不是一种类型 - 它是一种关闭类型检查并告诉静态类型系统“相信我,我知道我在做什么”的方法。编写dynamic o;
声明一个未经过类型检查的变量,而不是具有明确类型的变量。
当你写Object? o = something;
时,你告诉系统除了它是一个Object
或null
之外,不能假设任何关于o
的事情。你可以调用toString
和hashCode
,因为这些方法在Object
和Null
上定义,但如果你尝试执行o.foo()
,你会收到一个警告 - 它无法查看你是否能够执行该操作,因此它警告你代码可能是错误的。
如果你写dynamic o = something
,那么你告诉系统不要假设任何东西,也不要检查任何东西。如果你写o.foo()
,那么它就不会警告你。你告诉它:“与o
相关的任何东西都可以!相信我,我知道我在做什么”,所以它认为o.foo()
是可以的。
伴随着巨大的力量而来的是巨大的责任 - 如果你禁用变量的类型检查,那么就要由你来确保你不会做错任何事情。
第三版的Dart编程语言规范中的 Type dynamic 部分声明:
类型dynamic具有每个可能标识符和元数的方法,以及每个可能命名参数组合。这些方法的返回类型均为dynamic,它们的形式参数的类型也均为dynamic。类型dynamic还具有每个可能标识符的属性,这些属性的类型均为dynamic。
这意味着调用 dynamic
类型变量上的任何方法都不会产生警告。而对于一个类型为Object
的变量,则不是这种情况。例如:
dynamic a;
Object b;
main() {
a = "";
b = "";
printLengths();
}
printLengths() {
// no warning
print(a.length);
// warning:
// The getter 'length' is not defined for the class 'Object'
print(b.length);
}
在运行时,我认为,您不应该看到任何区别。
dynamic
不是一种类型,它只是禁用类型检查。 Object
是所有非空类型的“联合”,类型检查规则仍然适用。
比较这两种情况:
情况1(dynamic)
// a 'dynamic' variable can be assigned value of any type
dynamic a = 2;
// assign 'dynamic' value to any variable and code checker will not complain
int b = a;
// even when there is a bug
String c = a;
案例2(对象)
// It is OK to assign a 'int' value to an 'Object' variable, because 'int' is a subtype of 'Object'
Object a = 2;
// will get type error: "A value of type 'Object' can't be assigned to a variable of type 'int'"
int b = a;
// typecast is required when assign a 'Object' value to a variale of one of its subtypes.
int c = a as int;
除了Alexandre的回答中提到的实际差异,还存在语义差异。使用正确的方式将有助于更好地向其他程序员传达您的意图。
当您使用Object
时,您表明您知道正在使用的类型是Object
。例如:
int getHashCode(Object obj) {
return obj.hashCode;
}
由于hashCode
是Object
上的属性,因此我们使用Object
作为参数类型来指定该函数可以接受任何类型的Object
。
另一方面,使用dynamic
意味着Dart系统无法正确表达您想要使用的类型:
void setEmail(dynamic email) {
if (email is Email) {
_email = email;
} else if (email is String) {
_email = new Email.fromString(email);
}
}
由于Dart目前不支持联合类型,因此无法表达类型Email | String
,所以我们被迫使用dynamic
来接受所有类型,然后仅处理我们感兴趣的类型。
对象无法访问类的属性和方法,但是当使用动态语言时,您可以访问它们。
请查看以下示例:
class MyClass{
myFunction() => print("This works");
}
void main(){
dynamic a = new MyClass();
Object b = new MyClass();
a.myFunction(); // prints without error
b.myFunction(); // error : myFunction isn't defined for b
}
// I used to have the extension on dynamic and had
// problems that didn't occur when using the same extension on Object
extension UtilExtensions on Object {
bool get isStringNotEmpty => this is String && (this as String).isNotEmpty;
String get asStringNotEmpty => isStringNotEmpty ? this as String : null;
bool get isIntNotZero => this is int && (this as int) != 0;
int get asIntNotZero => isIntNotZero ? this as int : null;
Map<String, Object> get asPair {
if (this != null && this is Map) {
return (this as Map).cast<String, Object>();
}
return null;
}
Map<String, Object> get asFullPair {
if (this != null && this is Map) {
var ret = (this as Map).cast<String, Object>();
for (var key in ret.keys) {
var val = ret[key];
if (val is Map) {
ret[key] = val.asFullPair;
}
}
return ret;
}
return null;
}
}
dynamic是一个关键字,用于在变量中分配值,不进行类型检查。 Object是Dart中所有类的父类,它可以作为数据类型进行类型检查。
Object
和dynamic
实际上没有区别。 - lrn