2

我正在将 Nat Pryce 的Maybe课程翻译成 Delphi。
这里有一些背景: http: //www.natpryce.com/articles/000776.html

大部分都很简单,但是......
我如何将这个声明从 Java 翻译成 Delphi?

public abstract <U> Maybe<U> to(Function<? super T, ? extends U> mapping);

这是一个抽象的虚函数&to,它接受一个function命名mapping为参数,但我不知道如何建模。

对于上下文,这是完整的代码:

package com.natpryce.maybe;

import com.google.common.base.Function;
import com.google.common.base.Predicate;

import java.util.Collections;
import java.util.Iterator;

public abstract class Maybe<T> implements Iterable<T> {
    public abstract boolean isKnown();
    public abstract T otherwise(T defaultValue);
    public abstract Maybe<T> otherwise(Maybe<T> maybeDefaultValue);
    public abstract <U> Maybe<U> to(Function<? super T, ? extends U> mapping);
    public abstract Maybe<Boolean> query(Predicate<? super T> mapping);

    public static <T> Maybe<T> unknown() {
        return new Maybe<T>() {
            @Override
            public boolean isKnown() {
                return false;
            }

            public Iterator<T> iterator() {
                return Collections.<T>emptyList().iterator();
            }

            @Override
            public T otherwise(T defaultValue) {
                return defaultValue;
            }

            @Override
            public Maybe<T> otherwise(Maybe<T> maybeDefaultValue) {
                return maybeDefaultValue;
            }

            @Override
            public <U> Maybe<U> to(Function<? super T, ? extends U> mapping) {
                return unknown();
            }

            @Override
            public Maybe<Boolean> query(Predicate<? super T> mapping) {
                return unknown();
            }

            @Override
            public String toString() {
                return "unknown";
            }

            @Override
            @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
            public boolean equals(Object obj) {
                return false;
            }

            @Override
            public int hashCode() {
                return 0;
            }
        };
    }

    public static <T> Maybe<T> definitely(final T theValue) {
        return new DefiniteValue<T>(theValue);
    }

    private static class DefiniteValue<T> extends Maybe<T> {
        private final T theValue;

        public DefiniteValue(T theValue) {
            this.theValue = theValue;
        }

        @Override
        public boolean isKnown() {
            return true;
        }

        public Iterator<T> iterator() {
            return Collections.singleton(theValue).iterator();
        }

        @Override
        public T otherwise(T defaultValue) {
            return theValue;
        }

        @Override
        public Maybe<T> otherwise(Maybe<T> maybeDefaultValue) {
            return this;
        }

        @Override
        public <U> Maybe<U> to(Function<? super T, ? extends U> mapping) {
            return definitely(mapping.apply(theValue));
        }

        @Override
        public Maybe<Boolean> query(Predicate<? super T> mapping) {
            return definitely(mapping.apply(theValue));
        }

        @Override
        public String toString() {
            return "definitely " + theValue.toString();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            DefiniteValue<?> that = (DefiniteValue<?>) o;

            return theValue.equals(that.theValue);

        }

        @Override
        public int hashCode() {
            return theValue.hashCode();
        }
    }
}
4

2 回答 2

5

Java 代码利用了参数类型的协变和逆变。to 的参数to应该是一个带有一个参数的函数。参数的类型可以是T 或 的任何超类型T。该函数应返回类型U 或任何子类型的U值。

to函数将调用mapping并将T其当前持有的类型的值传递给它(如果它持有任何值),因此参数类型mapping需要是T可以分配给的东西。这包括T,Object以及层次结构中位于它们之间的任何其他类型。

同样,to将使用 的结果mapping来获取类型的值UMapping不必特别声明返回U,但它返回的任何类型都需要分配给U.

在 Delphi 中无法表达这些约束。您能做的最好的事情是请求一个使用字面意思的函数类型TU

function &to<U>(mapping: TFunc<T, U>): Maybe<U>;

可以U通过引入另一个类型参数来表达约束:

function &to<U: class; V: U>(mapping: TFunc<T, V>): Maybe<U>;

不过,我不知道类型参数是否可以用作同一参数列表中其他参数的约束。我也不确定编译器是否可以推断出该V上下文中的值,因此调用to会很麻烦。

另一方面,如果虚拟方法不能有新的泛型参数(如U),那么约束就无关紧要,因为您不能声明方法开始。

但是,根据参考实现,只有两个具体实现Maybe,因此一种可能性是实现to为非虚拟函数,然后手动检查运行时类型。不会很漂亮。像这样的东西:

if Self is TUnknown<T> then
  Result := unknown<U>
else
  Result := definitely(mapping(TDefiniteValue<T>(Self).value));
于 2013-10-03T14:19:09.733 回答
2

好吧,让我们忽略一开始的约束。Java 类型Function<T,R>映射到TFunc<T,R>Delphi 中。除此之外,该函数to在 type 上是通用的U,但在Maybe<T>. 所以这导致我们:

type
  Maybe<T> = class
    function &to<U>(mapping: TFunc<T, U>): Maybe<U>; virtual; abstract;
  end;

不幸的是,这不能编译。编译器发出E2533 虚拟、动态和消息方法不能有类型参数,这对我来说是一个新方法。这有点令人失望。

更新:正如 Rob 指出的那样,当他的答案出现时,我还没有考虑到约束,这些约束都不能用 Delphi 表达。

于 2013-10-03T14:19:42.350 回答