受限的接口实现 [英] Constrained interface implementation

查看:137
本文介绍了受限的接口实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Haskell(和Rust等)中,我可以有受其他实例约束的实例:

  data pair ab =对ab 

实例(等式a,等式b)=> Eq(Pair a b)其中
Pair a b == Pair a'b'= a == a'&& b == b'

使用Java接口我不行。我必须要求类型参数 Pair 始终实现 Eq ,否则我不能实现 Eq< Pair< A,B>> 完全可以:

 接口等式< A> {
public boolean eq(A other);
}

class对< A扩展Eq< A>,B扩展Eq< B>实现等式> {
A a;
B b;
public boolean eq(Pair< A,B> other){
return a.eq(other.a)&& b.eq(other.b);


$ / code $ / pre

我想要这样的: p>

  class Pair< A,B>实现等式>如果(A实现Eq& B实现Eq< B>){...} 



到目前为止,互联网已经告诉我,我所需的功能在Java中不直接支持。尽管如此,我认为这是界面(再)可用性中相当关键的因素。我想知道是否有解决方案或解决方案大致相同。

解决方案

我的想法是让比较者在课堂之外。这是Scala采取的方法,同时通过隐含的帮助使其易于消化。 。而且他们还有构建比较器的方法,比如

  public< A,B>比较<对< A,B>> pairCmp(Comparator< A> ca,Comparator< B> cb){... 

相当繁琐的工作。
Haskell在内部执行相同的操作,将类型类实现的字典传递给但是type-class接口和类型推断一起使得它更令人愉快。


据我所知,在Java中,没有办法如何声明条件实例。但是更多的OO方法将是允许相等的对子类:

  class PairEq< A extends Eq< A>,B扩展了等式B> 
延长Pair< A,B>
实现Eq< Pair< A,B>> {b
$ b ...

还有一些手动过程涉及到您需要决定何时使用 Pair 以及何时使用 PairEq 。但是通过方法重载,我们可以通过声明智能构造函数来使其更容易使用。由于Java总是选择最具特色的一个,所以无论何时我们需要创建一对,我们只需使用 mkPair ,Java就会选择返回 PairEq ,如果参数适当地执行 Eq

 公共静态< A,B>对< A,B个mkPair(A a,B b){
返回新对< A,B>(a,b);
}

public static< A extends Eq< A>,B extends Eq< B>> PairEq< A,B个mkPair(A a,B b){
返回新的PairEq< A,B>(a,b);

$ / code>

完整的示例代码:

 界面Eq< A> {
public boolean eq(A other);
}

公开课对< A,B> {
public final A a;
public final B b;

公共对(A a,B b){
this.a = a;
this.b = b;
}

public static< A,B>对< A,B个mkPair(A a,B b){
返回新对< A,B>(a,b);
}

public static< A extends Eq< A>,B extends Eq< B>> PairEq< A,B个mkPair(A a,B b){
返回新的PairEq< A,B>(a,b);
}
}

class PairEq ,B扩展Eq
延长Pair< A,B>
实现Eq< Pair< A,B>>
{
public PairEq(A a,B b){
super(a,b);
}

@Override
public boolean eq(Pair< A,B> that){
return a.eq(that.a)&& b.eq(that.b);
}
}


In Haskell (and Rust, and others) I can have instances that are constrained by other instances:

data Pair a b = Pair a b

instance (Eq a, Eq b) => Eq (Pair a b) where 
    Pair a b == Pair a' b' = a == a' && b == b'

With Java interfaces I can't. I must require the type parameters of Pair to always implement Eq, or I can't implement Eq<Pair<A, B>> at all:

interface Eq<A> {
    public boolean eq(A other);
}

class Pair<A extends Eq<A>, B extends Eq<B>> implements Eq<Pair<A, B>> {
    A a;
    B b;
    public boolean eq(Pair<A, B> other){
        return a.eq(other.a) && b.eq(other.b);
    }
}

I'd like to have something like:

class Pair<A, B> implements Eq<Pair<A, B>> if (A implements Eq<A> && B implements Eq<B>) {...}

So far the Internet has told me that my desired functionality isn't directly supported in Java. Nevertheless I find this a rather critical factor in the (re)usability of interfaces. I'd like to know if there are workarounds or solutions that approximately cover the same ground.

解决方案

One canonical solution that comes to my mind is to make the comparator external to the class. This is the approach that Scala takes, while making it easier digestible with the help of implicits. And they you'd have methods for constructing comparators, such as

public <A, B> Comparator<Pair<A,B>> pairCmp(Comparator<A> ca, Comparator<B> cb) { ...

This is however quite cumbersome to work with. Haskell does the same thing internally, passing dictionaries of type-classes implementitions under the hood, but the type-class interface together with type inference makes it much more pleasant.

As far as I know, in Java there is no way how to declare conditional instances. But a more OO approach would be to have a sub-class for pairs that allow equality:

class PairEq<A extends Eq<A>, B extends Eq<B>>
  extends Pair<A,B>
  implements Eq<Pair<A, B>> {

...

There is again some manual process involved, as you need to decide when to use Pair and when PairEq. But with method overloading, we could make it easier to use by declaring smart constructors. As Java always picks the most specific one, whenever we need to create a pair, we just use mkPair and Java will pick the one returning PairEq, if the arguments implement Eq appropriately:

public static <A,B> Pair<A,B> mkPair(A a, B b) {
    return new Pair<A,B>(a, b);
}

public static <A extends Eq<A>, B extends Eq<B>> PairEq<A,B> mkPair(A a, B b) {
    return new PairEq<A,B>(a, b);
}

Complete sample code:

interface Eq<A> {
    public boolean eq(A other);
}

public class Pair<A,B> {
    public final A a;
    public final B b;

    public Pair(A a, B b) {
        this.a = a;
        this.b = b;
    }

    public static <A,B> Pair<A,B> mkPair(A a, B b) {
        return new Pair<A,B>(a, b);
    }

    public static <A extends Eq<A>, B extends Eq<B>> PairEq<A,B> mkPair(A a, B b) {
        return new PairEq<A,B>(a, b);
    }
}

class PairEq<A extends Eq<A>, B extends Eq<B>>
    extends Pair<A,B>
    implements Eq<Pair<A,B>>
{
    public PairEq(A a, B b) {
        super(a, b);
    }

    @Override
    public boolean eq(Pair<A,B> that) {
        return a.eq(that.a) && b.eq(that.b);
    }
}

这篇关于受限的接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆