1

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

class Foo(x: Int, z: String) { 
  def this(z: String) = this(0, z);   
}

但是我怎样才能重载一个具有两种完全不同类型的参数的类,如下所示(想象我可以通过名称或数字id来识别用户)

class User(userId: Int) {
  ...
}

class User(userName: String) {
  ...
}
4

3 回答 3

3

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

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

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

class User private(identifier : Either[String, Int]) {
  def this(id : Int) = this(Right(id))
  def this(name : String) = this(Left(name))
}

但是,您可能还希望使用户标识符的性质更加明确,并将其编码为您自己的代数数据类型

trait UserIdentifier
object UserIdentifier {
  case class ById(id : Int) extends UserIdentifier
  case class ByName(name : String) extends UserIdentifier
}

class User(id : UserIdentifier) {
  def this(id : Int) = this(UserIdentifier.ById(id))
  def this(name : String) = this(UserIdentifier.ByName(name))
}

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

于 2013-04-16T09:06:26.943 回答
2

或者,您可以这样做

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
  }

}
于 2013-04-15T13:17:15.167 回答
1

你可以这样做:

class User private() {
  def this( userName: String ) = { this(); ??? }
  def this( userId: Int ) = { this(); ??? }
}

关键字使private无参数构造函数私有。这意味着您的其他辅助构造函数不需要向主构造函数传递任何内容(有效地使两个辅助构造函数独立),但调用者仍然无法在不传递任何参数的情况下实例化该类。请注意,当您的类具有要从 construtors 参数初始化的 val 时,使用此模式可能会很棘手。

于 2013-04-15T13:26:20.200 回答