【问题标题】:How to translate java generics into Delphi如何将java泛型翻译成Delphi
【发布时间】:2013-10-03 13:39:08
【问题描述】:

我正在将 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);

这是一个抽象虚函数&amp;to,它接受一个名为mappingfunction 作为参数,但我不确定如何建模。

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

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();
        }
    }
}

【问题讨论】:

  • 您可以将此类用作 Oasis 专辑标题生成器
  • 你可以看看Spring.Nullable<T>
  • 顺便说一句,上面的代码避免的真正问题是 Java 独有的,Delphi 中的习惯用法是在调用 X.Something 之前检查if Assigned(X)那可能是空的。我认为 java 令人作呕的异常模型和语义(例如,在 Java 代码库中是否见过连续 30 个检查异常捕获的块?)是上述代码和类型以及博客文章的部分原因。
  • @WarrenP,我知道,我想要一些关于如何解决 Delphi 缺乏协变等问题的练习。尽管它们看起来与 java、C# 和 Delphi 中泛型的feel 很相似。 Java 的泛型感觉很棒,但是还有 type erasure sigh.
  • 本质上,C# 和 Java 中涉及协方差的大多数问题最好在 Delphi 中以另一种方式解决,通常根本不需要泛型。换句话说,回到第 1 格并编写您自己的手卷解决方案,没有泛型。

标签: java delphi generics delphi-xe2


【解决方案1】:

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

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

同样,to 将使用mapping 的结果来获取U 类型的值。 Mapping 不必特别声明为返回 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));

【讨论】:

  • 请记住,我没有Delphi,当然不是支持泛型的版本,所以如果我的想法是合理的,但是语法关闭,请修复语法。
  • 如果你没有Delphi,你怎么能在delphi标签中有一个金徽章?
  • @Johan 从前他确实有Delphi,但是为什么需要编译器来回答问题?
  • @Johan 为 Rob 加油。他白天是 C++ 大师,但仍然记得 Delphi。我认为他是 FWIW 堆栈上最好的常规 Delphi 回答者。他的答案总是写得很漂亮,而且总是充满洞察力。而且他几乎从不犯错,不像我能想到的其他人...... ;-)
  • 我获得了金牌,因为我在 David 加入之前回答了一堆 Delphi 问题。
【解决方案2】:

好吧,让我们忽略一开始的约束。 Java 类型 Function&lt;T,R&gt; 映射到 Delphi 中的 TFunc&lt;T,R&gt;。除此之外,函数toU 类型的泛型,但是Maybe&lt;T&gt; 的方法。所以这导致我们:

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

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

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

【讨论】:

  • 如果 covariant/contravariant/type-constraint-Object-Pascal 在未来的某些 LLVM-Delphi 编译器中成为一种可能性,我不会感到惊讶,但就目前而言,我们离这还很遥远。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 2020-03-06
  • 2015-09-22
  • 1970-01-01
  • 2015-11-14
  • 1970-01-01
相关资源
最近更新 更多