Eiffel:一旦函数具有通用或锚定结果。尝试创建常量

Eiffel: once function has generic or anchored result. Trying to create constants

我正在尝试创建一些终端日志记录颜色以便能够更清楚地看到我的错误。这样做在我看来很明显我必须创建如下常量。因为我不想每次调用我的常量时都创建一个实例,所以我做这样的事情是有意义的,但是编译器似乎和我的概念不一样...

A once function has generic or anchored result 什么是 anchored 结果

既然编译器永远说了算,我说了算,为什么我错了他是对的??

class
    TERMINAL_COLOR

create
    make

feature -- Initialization

    make (a_fg: like foreground; a_bg: like background)
        do
            foregound := a_fg
            background := a_bg
        end

feature -- Status report

    foreground: INTEGER

    background: INTEGER

feature -- Colors

    Black: like Current
        once -- compiler doesn't agree with me
            create Result.make (30, 40)
        ensure
            instance_free: class
        end

end

事实上,一旦函数不允许 return 锚定类型或正式泛型类型的值。原因在于 once 函数的语义:无论当前对象类型如何,它的主体只执行一次(我忽略了更复杂的递归情况)。

在您的示例中,可能有 class TERMINAL_COLOR 的后代,比如 TOUCH_PAD_COLOR(无论它是什么意思):

class
    TOUCH_PAD_COLOR
inherit
    TERMINAL_COLOR
create
    make
feature
    touch_color: like Current
            -- Color for visual indication of user interaction.
        ...
end

让我们看看下面的代码会发生什么:

t: TERMINAL_COLOR
p: TOUCH_PAD_COLOR
...
t := {TERMINAL_COLOR}.black
p := {TOUCH_PAD_COLOR}.black

因为blackreturns like Current,两个赋值都是有效的:black的类型在第一次调用时是TERMINAL_COLORTOUCH_PAD_COLOR - 在第二个。然而,特征black的主体只执行一次,即在第一次调用时。计算对象的类型是TERMINAL_COLOR。在第二个赋值中,先前计算的对象被 returned 而没有执行函数的主体 black。对象的类型仍然是相同的:TERMINAL_COLOR。但现在此对象已附加到 TOUCH_PAD_COLOR 类型的实体 p。在 p 上拨打电话,例如p.touch_color 会导致崩溃,因为 class TERMINAL_COLOR.

中没有方法 touch_color

就术语而言,锚定类型表示根据某些其他实体声明的类型。例如like Current指的是当前class.

的类型

免责声明。曾经的特征有多种,上面的场景处理的是最常见的情况。

锚类型是当你使用 "like feature" 时(注意你也可以使用 "like {FOO}.bar")。

此外,不要忘记 Once 是 "once per class"(不是按类型)。 这就是为什么 once 函数的结果类型不能使用任何正式泛型的原因。 例如

class FOO [G]
feature
    bar: STRING
        once
           Result := generating_type
        end
end

(create {FOO [INTEGER]}).bar 将 return 与 (create {FOO [STRING]}).bar.

相同的对象

所以,现在如果 bar 会 return G 在 class FOO 中,它会造成麻烦,因为没有办法 return 一个值符合任何形式的(INTEGER、STRING、...)。

这就是为什么泛型被禁止用于一次结果类型的原因。

相同的逻辑适用于 like feature_name 等锚类型,因为 feature_name 可以在后代中与其他类型重新定义。