Scala 重载具有不同参数类型的构造函数

Scala 重载具有不同参数类型的构造函数,scala,constructor-overloading,Scala,Constructor Overloading,我知道我们可以在Scala中重载类构造函数,如下所示- class Foo(x: Int, z: String) { def this(z: String) = this(0, z); } 但是我如何重载一个具有两种完全不同类型参数的类,如下所示(假设我可以通过名称或数字id来识别用户) 或者,你也可以这样做 object User { def apply(userId: Int) = new UserI(userId) def apply(name: String) =

我知道我们可以在Scala中重载类构造函数,如下所示-

class Foo(x: Int, z: String) { 
  def this(z: String) = this(0, z);   
}
但是我如何重载一个具有两种完全不同类型参数的类,如下所示(假设我可以通过名称或数字id来识别用户)


或者,你也可以这样做

object User {
  def apply(userId: Int) = new UserI(userId)
  def apply(name: String) = new UserS(name)

  class UserI(userId: Int)
  class UserS(userName: String)
}
并以这种方式使用它:

  val u1 = User(1)
  val u2 = User("a")
如果你有很多公共逻辑,你可以把它放到一个公共抽象类中

object User {
  def apply(userId: Int) = new UserI(userId)
  def apply(name: String) = new UserS(name)


  class UserI(userId: Int) extends AUser
  class UserS(userName: String) extends AUser

  abstract class AUser{
    // common logic for both classes
  }

}

或者,你也可以这样做

object User {
  def apply(userId: Int) = new UserI(userId)
  def apply(name: String) = new UserS(name)

  class UserI(userId: Int)
  class UserS(userName: String)
}
并以这种方式使用它:

  val u1 = User(1)
  val u2 = User("a")
如果你有很多公共逻辑,你可以把它放到一个公共抽象类中

object User {
  def apply(userId: Int) = new UserI(userId)
  def apply(name: String) = new UserS(name)


  class UserI(userId: Int) extends AUser
  class UserS(userName: String) extends AUser

  abstract class AUser{
    // common logic for both classes
  }

}
您可以这样做:

class User private() {
  def this( userName: String ) = { this(); ??? }
  def this( userId: Int ) = { this(); ??? }
}
private
关键字使no-arg构造函数成为私有的。这意味着您的其他辅助构造函数不需要向主构造函数传递任何内容 (有效地使两个辅助构造函数独立),但调用方仍然无法在不传递任何参数的情况下实例化该类。 请注意,当您的类具有要从Constructors参数初始化的VAL时,此模式可能很难使用。

您可以执行以下操作:

class User private() {
  def this( userName: String ) = { this(); ??? }
  def this( userId: Int ) = { this(); ??? }
}
private
关键字使no-arg构造函数成为私有的。这意味着您的其他辅助构造函数不需要向主构造函数传递任何内容 (有效地使两个辅助构造函数独立),但调用方仍然无法在不传递任何参数的情况下实例化该类。 请注意,当您的类具有要从construtors参数初始化的VAL时,此模式可能很难使用

(假设我可以通过名称或数字id识别用户)

您几乎肯定不希望通过在类中设置可选字段来实现这一点。相反,您应该将用户以各种方式标识的事实编码到程序的类型和结构中

一种方法是使用Scala内置的
类型对用户标识符进行编码:

class User private(identifier : Either[String, Int]) {
  def this(id : Int) = this(Right(id))
  def this(name : String) = this(Left(name))
}
但是,您可能还希望使用户标识符的性质更加明确,并将其编码为您自己的:

通过这样做,您可以防止出现问题,例如有人试图查找由id标识的用户的姓名。第二种方法还允许您在将来扩展
UserIdentifier
的概念,以防可以通过其他构造识别用户

(假设我可以通过名称或数字id识别用户)

您几乎肯定不希望通过在类中设置可选字段来实现这一点。相反,您应该将用户以各种方式标识的事实编码到程序的类型和结构中

一种方法是使用Scala内置的
类型对用户标识符进行编码:

class User private(identifier : Either[String, Int]) {
  def this(id : Int) = this(Right(id))
  def this(name : String) = this(Left(name))
}
但是,您可能还希望使用户标识符的性质更加明确,并将其编码为您自己的:


通过这样做,您可以防止出现问题,例如有人试图查找由id标识的用户的姓名。第二种方法还允许您在将来扩展
用户标识符的概念,以防可以通过其他构造识别用户。

这两种情况之间没有真正的区别;两者都没有冲突。我不确定什么东西没有达到你想要或期望的效果,或者,真的,你遇到了什么确切的问题;两者都没有冲突。我不确定是什么做不到你想要或期望的,或者,真的,你遇到了什么问题。绝妙的把戏!它工作得很好。如果用户是一个案例类呢?很好的技巧!它工作得很好。如果用户是案例类呢?非常感谢您花时间回复。第一种方法的问题是它限制了两种类型的解决方案,不能扩展到更多类型。但我绝对支持第二种方法。非常感谢您花时间回复。第一种方法的问题是它限制了两种类型的解决方案,不能扩展到更多类型。但我绝对支持第二种方法。