我正在将Nat Pryce的Maybe
课程翻译成德尔福
这是一些背景: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();
}
}
}
答案 0 :(得分:5)
Java代码利用参数类型中的协方差和逆变。 to
的参数应该是一个带有一个参数的函数。参数的类型可以是T
或任何超类型T
。该函数应返回U
类型的值或U
的任何子类型。
to
函数将调用mapping
并将其当前保存的类型T
的值传递给它(如果它根本保存任何值),因此参数类型为mapping
需要是T
可以分配的内容。这包括T
,Object
以及层次结构中它们之间的其他类型。
同样,to
将使用mapping
的结果来获取类型U
的值。 Mapping
不必声明为具体返回U
,但无论何种类型返回都需要赋予U
。
在Delphi中无法表达这些约束。您可以做的最好的事情是请求一个使用字面T
和U
的函数类型:
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));
答案 1 :(得分:2)
好吧,让我们忽略开始时的约束。 Java类型Function<T,R>
映射到Delphi中的TFunc<T,R>
。除此之外,函数to
在U
类型上是通用的,但是Maybe<T>
的方法。这导致我们:
type
Maybe<T> = class
function &to<U>(mapping: TFunc<T, U>): Maybe<U>; virtual; abstract;
end;
不幸的是,这不会编译。编译器发出 E2533虚拟,动态和消息方法不能有类型参数这对我来说是一个新的参数。这令人失望。
更新:正如Rob指出的那样,当他的答案出现时,我还没有考虑约束,这些约束都不能在Delphi中表达。