gpt4 book ai didi

ceylon - 满足 'Iterable'接口(interface)不涉及Null

转载 作者:行者123 更新时间:2023-12-01 13:18:58 28 4
gpt4 key购买 nike

我正在尝试创建一个满足接口(interface) Iterable 的类“Gprogram” (这样我就可以在我的 Gprogram 中迭代 Gcommand)。但是,我只能使用类型 Iterable<Gcommand|Null,Nothing> 使其可迭代我宁愿在哪里 Iterable<Gcommand,Nothing> .问题是:当我尝试使用 Iterable<Gcommand,Nothing> 时,我得到这个错误:

specified expression must be assignable to declared type of 'next' of 'Iterator' with strict null checking: 'Null|Gcommand|finished' is not assignable to 'Gcommand|Finished' (the assigned type contains 'null')

此错误是指此代码段:

next() => index>=size
then finished
else gcommands[index++];

取自此处的完整实现:​​

shared class Gprogram( Gcommand+ gcommands ) satisfies Iterable<Gcommand|Null,Nothing> {

shared actual default Iterator<Gcommand|Null> iterator() {
if (gcommands.size > 0) {
return object
satisfies Iterator<Gcommand|Null> {
variable Integer index = 0;
value size = gcommands.size;
next() => index>=size
then finished
else gcommands[index++];
string => gcommands.string + ".iterator()";
};
}
else {
return emptyIterator;
}
}
}

问题在我看来是类型检查器无法意识到 next方法永远不能返回 null(实现这一点将涉及对整数值的推理,而类型检查器无法做到这一点)。因此,所有的希望都破灭了,对吧..?

一个令人烦恼的问题仍然存在:List 是如何实现的?设法做我做不到的事??让我们看一下 iterator 的实现对于 List类:

    shared actual default Iterator<Element> iterator() {
if (size>0) {
return object​
satisfies Iterator<Element> {
variable Integer index = 0;
value size = outer.size;
next() => index>=size​
then finished​
else getElement(index++);
string => outer.string + ".iterator()";
};
}
else {
return emptyIterator;
}
}

哪里getElement函数看起来像这样:

    Element getElement(Integer index) {
if (exists element = getFromFirst(index)) {
return element;
}
else {
assert (is Element null);
return null;
}
}

( full source code )

可以看出getElement非常有能力返回 Null 值。但是怎么会是List呢? Iterable的满意度接口(interface)没有提到 Nulls,就像我的实现是被迫的?相关的“满足”声明位于 List的父类(super class)型,Collection .看这里:

​shared interface Collection<out Element=Anything>
satisfies {Element*} {

( full source code )

看,妈妈!没有 {Element|Null*} !

最佳答案

是的,的确,Ceylon 编译器在检查查找表达式(方括号)的可空性时不会对整数进行推理,因为 Ceylon 不是依赖类型的语言。

更好的(实际可行的)方法是使用 else 运算符:

next() => gcommands[index++] else finished;

或者可以说更好的是 getOrDefault 方法:

next() => gcommands.getOrDefault(index++, finished);

List 可以返回 null 的原因是因为它的 narrowing 断言:

assert (is Element null);

作为任何类型缩小断言,null 的类型在断言之后从 Null 缩小为 Null&Element

然而,值得注意的是,与您日常的缩小条件不同,这个条件影响的不是局部值,而是匿名类(即 object 声明),即 null

同样有趣的是,它是对 null 的引用类型缩小到 Null&Element,而不是 Null 类型本身改变父类(super class)型。

也就是说,如果您有一个类型为 Null 的表达式,它仍然无法分配给 Element

例如,考虑以下声明:

Foo foo<Foo>()
{
Null n = null;
assert(is Foo null);
// return n; // Doesn’t work.
return null; // Works.
}

这里,nNull类型,nullNull&Foo类型。后者可分配给 Foo 并且可以无错返回。但是,第一个不是,会产生错误。

这是由于 inability to narrow type’s supertypes and subtypes (与缩小值的类型相反,后者已经成为可能)。

缩小 null 类型“有效”(而不是简化为 Nothing)的原因是类型参数本身与 ObjectNull 类型,在 Anything 下面的类型层次结构中属于自己的分支。

这是因为类型参数可能在运行时被实现为AnythingNull(或\Inull)、Object ,或 Object 的任何子类型。

实际上,List 中的 getElement 方法的行为与此变体相同:

Element getElement(Integer index)
{
assert(is Element element = getFromFirst(index)).
return element;
}

但语言模块中的版本性能更高,因为 existsis Element 更快。语言模块中的版本仅在列表包含 null 元素时执行缓慢的运行时类型检查。

关于ceylon - 满足 'Iterable'接口(interface)不涉及Null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51646787/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com