Scala: Exposing a class in another package and running into problems

huangapple go评论71阅读模式
英文:

Scala: Exposing a class in another package and running into problems

问题

以下是您要翻译的内容:

我有一个包内的特质中的类

trait NRC {
    final case class Singleton(e: TupleExpr) extends BagExpr {
       val tp: BagType = BagType(e.tp)
    }
}
我想要使用另一个类中的对象来暴露它我已经这样做了

case object Exposed extends NRC {
  def apply(x: TupleExpr): BagExpr = {
    Singleton(x)
  }
}
现在当我使用这个实现时遇到问题

我这样使用它注意WrappedDataset是另一个扩展NRC的类):

val e1: WrappedDataset = ds.wrap()
val r1 = e1.customMap(x => Singleton(x))

第二行出现类型不匹配错误:

类型不匹配。需要:Singleton.TupleExpr,找到:e1.TupleExpr

类型不匹配。需要:e1.BagExpr,找到:Singleton.BagExpr

对我来说不太合理,因为它们本质上是指同一件事情。

可以通过这样的类型转换来修复错误:

val r1 = e1.flatMap(x => Singleton(x.asInstanceOf[Exposed.TupleExpr]).asInstanceOf[e1.BagExpr])

但这不是一个令人满意的解决方案,因为我需要将这个逻辑隐藏起来。
在Singleton案例对象中是否有处理这个问题的方法,或者可能有其他解决方法?

英文:

I have a class within a trait in one package:

trait NRC {
    final case class Singleton(e: TupleExpr) extends BagExpr {
       val tp: BagType = BagType(e.tp)
    }
}

And I want to expose it using an object in another class which I have done like so:

case object Exposed extends NRC {
  def apply(x: TupleExpr): BagExpr = {
    Singleton(x)
  }
}

Now when it comes to using this implementation I run into issues:

I am using it like so (Note that WrappedDataset is another class which extends NRC):

val e1: WrappedDataset = ds.wrap()
val r1 = e1.customMap(x => Singleton(x))

On the second line above I get a type mismatch errors:

> Type mismatch. Required: Singleton.TupleExpr, found: e1.TupleExpr

&

> Type mismatch. Required: e1.BagExpr, found: Singleton.BagExpr

Which to me doesn't really make sense as they are referring to the same thing essentially.

The errors can be fixed using casting like this:

val r1 = e1.flatMap(x => Singleton(x.asInstanceOf[Exposed.TupleExpr]).asInstanceOf[e1.BagExpr])

However this isn't an adequate solution as I need this logic to be hidden.
Is there some way to handle this in the case object Singleton, or another work around that could be possible?

答案1

得分: 4

你将所有东西都称为“Singleton”,这让人很难跟踪和理解你的意图,也没有关于TupleExpr的定义,所以我只能猜测发生了什么...

但我猜你的问题是你没有意识到内部类型定义是“实例”特定的:

trait Foo { case class X(x: String) } 
object Bar extends Foo
object Baz extends Foo

class Bat extends Foo 

Bar.X("foo") == Baz.X("foo") // false
new Bat().X("foo") == new Bat().X("foo") // false

这返回false,因为不仅Bar.XBaz.X是两个不同的类(BarBaz实际上是不同的类型),而且new Bat().Xnew Bat().X也是两个不同的类,因为它们属于不同的实例(尽管是相同类型的实例)。

英文:

You call everything Singleton, making it pretty hard to follow and understand what you are trying to do, there also no definition of TupleExpr anywhere, so I can only guess what is going on ...

But I am guessing your problem is you do not realize that inner type definitions are instance specific:

trait Foo { case class X(x: String) } 
object Bar extends Foo
object Baz extends Foo

class Bat extends Foo 

Bar.X("foo") == Baz.X("foo") // false
new Bat().X("foo") == new Bat().X("foo") // false

This returns false because not only Bar.X and Baz.X are two different classes (Bar and Baz are actually different types), but new Bat().X and new Bat().X are also different classes because they belong to different instances (albeit of the same type).

答案2

得分: 2

Sure, here is the translated content:

除此之外,我认为 @Dima 的回答已经很清楚了,我想提供更多信息和细节。

看起来你正在尝试使用类似于 Java 内部类 的东西。Scala 内部类 的工作方式不同。此外,你还有特质(traits),这是你在这种情况下使用的内容。

> 在 Scala 中,允许 类具有其他类作为成员
> 与 Java 类似的语言不同,这些 内部类是外部对象的一部分

你在文档中已经有了相当不错的 Scala 示例,但我还想添加一些 Java 代码。


在 Java 中,你可以做到以下事情

  1. 声明一个类 A,其中包含一个内部类 InnerClass 和一个静态内部类 StaticInnerClass
class A {
    class InnerClass {}
    static class StaticInnerClass {}
    public void receiveInnerClass(InnerClass innerClass) {}
    public static void receiveStaticInnerClass(InnerClass staticInnerClass) {}

    public InnerClass newInnerClass() {
        return new InnerClass();
    }

    public static StaticInnerClass newStaticInnerA() {
        return new StaticInnerClass();
    }
}
  1. 在另一个类中,你可以共享来自两个不同的 A 实例的内部类。
A anA = new A();
A anotherA = new A();
A.InnerClass aInnerClass = anA.newInnerClass();
A.InnerClass anotherInnerClass = anotherA.newInnerClass();

anA.receiveInnerClass(aInnerClass);
anA.receiveInnerClass(anotherInnerClass);

在 Scala 中,有一些关于内部类你可以做和不能做的事情

没有静态类,你有 类(classes)单例对象(Singleton Objects)

  1. 我们可以定义一个类 A,其中包含一个内部类 InnerClass 和一个单例对象 A,其中包含一个内部类 InnerClassFromCompanion
class A {
  class InnerClass

  def newInnerClass: InnerClass = new InnerClass
  def receiveInnerClass(innerClass: InnerClass): Unit = ()
  def receiveInnerAFromCompanion(innerAFromCompanion: A.InnerClassFromCompanion) = ()
}

object A {
  class InnerClassFromCompanion

  def newInnerClassFromCompanion: InnerClassFromCompanion = new InnerClassFromCompanion
  def receiveInnerClassFromCompanion(innerClassFromCompanion: InnerClassFromCompanion): Unit = ()
  def receiveInnerClass(innerClass: A.InnerClass) = ()
}
  1. 从另一个地方,有一些事情是可以做的,而另一些则不能。
val anA: A = new A
val innerClassFromAnA: A.InnerClass = anA.newInnerClass // 这将无法编译,因为它试图在单例对象 `A` 中找到 `InnerClass`
val innerClassFromAnA: anA.InnerClass = anA.newInnerClass // 我们可以注意到它被标记为 `anA.InnerClass`,而不是 `A.InnerClass`
val anotherA: A = new A
val innerClassFromAnotherA: anotherA.InnerClass = anotherA.newInnerClass // 关于它的类型标记也是一样的

// 以下行将失败,显示类型不匹配
anA.receiveInnerClass(innerClassFromAnotherA) // 需要 `anA.InnerClass`,找到 `anotherA.InnerClass`
anotherA.receiveInnerClass(innerClassFromAnA) // 需要 `anotherA.InnerClass`,找到 `anA.InnerClass`
  1. 在你的情况下,当你想在不同的类中共享内部类时,一种解决方法是从你的 特质(trait) 中提取内部类,并将其移动到单例对象中,或者直接不声明它为内部类。
val anInnerFromACompanionA = new A.InnerClassFromCompanion
val anotherInnerFromACompanionA = new A.InnerClassFromCompanion

A.receiveInnerClassFromCompanion(anInnerFromACompanionA)
A.receiveInnerClassFromCompanion(anotherInnerFromACompanionA)
英文:

Beside I think the @Dima's answer is pretty clear, I would like to provide more info and details.

Looks like you are trying to use something similar to java inner classes. Scala Inner classes works different. Also you have traits which is what you are using in this case.

> In Scala it is possible to let classes have other classes as members.
> As opposed to Java-like languages where such inner classes are members
> of the enclosing class
, in Scala such inner classes are bound to the
> outer object
.

You have pretty good scala examples in the docs, but I would like to add also Java code too.


In Java, you can do the following

  1. declare a class A with an inner class InnerClass and a static inner class StaticInnerClass
class A {
    class InnerClass {}
    static class StaticInnerClass {}
    public void receiveInnerClass(InnerClass innerClass) {}
    public static void receiveStaticInnerClass(InnerClass staticInnerClass) {}

    public InnerClass newInnerClass() {
        return new InnerClass();
    }

    public static StaticInnerClass newStaticInnerA() {
        return new StaticInnerClass();
    }
}
  1. In another class, you can share inner classes from two different instances of A
A anA = new A();
A anotherA = new A();
A.InnerClass aInnerClass = anA.newInnerClass();
A.InnerClass anotherInnerClass = anotherA.newInnerClass();

anA.receiveInnerClass(aInnerClass);
anA.receiveInnerClass(anotherInnerClass);

In Scala there are some things you can and you can't do with inner classes

There is no static classes, you have classes and Singleton Objects.

  1. We can define a class A with an inner class InnerClass and a singleton object A with an inner class InnerClassFromCompanion
class A {
  class InnerClass

  def newInnerClass: InnerClass = new InnerClass
  def receiveInnerClass(innerClass: InnerClass): Unit = ()
  def receiveInnerAFromCompanion(innerAFromCompanion: A.InnerClassFromCompanion) = ()
}

object A {
  class InnerClassFromCompanion

  def newInnerClassFromCompanion: InnerClassFromCompanion = new InnerClassFromCompanion
  def receiveInnerClassFromCompanion(innerClassFromCompanion: InnerClassFromCompanion): Unit = ()
  def receiveInnerClass(innerClass: A.InnerClass) = ()
}
  1. from another place there will be things that can be done and some others can't
val anA: A = new A
val innerClassFromAnA: A.InnerClass = anA.newInnerClass // this won't compile because it's trying to find `InnerClass` inside singleton object `A`
val innerClassFromAnA: anA.InnerClass = anA.newInnerClass // we can notice that is typed as `anA.InnerClass`, not as an `A.InnerClass`
val anotherA: A = new A
val innerClassFromAnotherA: anotherA.InnerClass = anotherA.newInnerClass // same here about how is typed

// the following lines will fail saying typemismatch
anA.receiveInnerClass(innerClassFromAnotherA) // required `anA.InnerClass`, found `anotherA.InnerClass` 
anotherA.receiveInnerClass(innerClassFromAnA) // required `anotherA.InnerClass`, found `anA.InnerClass`
  1. in your case, where you want to share inner classes in different classes, a way of solving that is to extract the inner class from the trait you have and move to a singleton object or directly not declare it as an inner class
val anInnerFromACompanionA = new A.InnerClassFromCompanion
val anotherInnerFromACompanionA = new A.InnerClassFromCompanion

A.receiveInnerClassFromCompanion(anInnerFromACompanionA)
A.receiveInnerClassFromCompanion(anotherInnerFromACompanionA)

huangapple
  • 本文由 发表于 2023年6月6日 01:06:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76408608.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定