【问题标题】:how can I call a method in auxiliary constructor?如何在辅助构造函数中调用方法?
【发布时间】:2011-06-28 04:55:45
【问题描述】:
class foo(val x:Int){
  def convertToInt(z:string) = {do somthing to convert a string to an integer}
  def this(y:string) = this(convertToInt(y))
}

在辅助构造函数 (this(y:string)) 中调用 convertToInt 会导致此错误:

error: not found: value convertToInt

我知道我可以使用单例对象并将所有静态函数(如 convertToInt)打包到其中,但这是一个好的解决方案吗?

object foo{
    def convertToInt(z:string) = {do somthing to convert a string to an integer}
}   
class foo(val x:Int){
    def this(y:string) = this(foo.convertToInt(y))
}

【问题讨论】:

    标签: scala


    【解决方案1】:

    我认为在这种情况下最好的解决方案是使用工厂方法而不是公共构造函数。

    所以你可以定义你的构造函数private并在伴随对象中提供工厂apply方法:

    class Foo private (val x:Int) 
    
    object Foo {
        def apply(i: Int) = new Foo(i)
        def apply(s: String) = new Foo(convertToInt(s))
    
        def convertToInt(s: String) = s.toInt
    }   
    
    println(Foo(512).x)
    println(Foo("256").x)
    

    您可以在此处找到有关构造函数与工厂方法的更多信息:

    Constructors vs Factory Methods

    Scala 也是如此。

    更新

    作为替代解决方案的示例,我提出了非常通用解决方案。 Foo 类现在可以与任何曾经存在或将来可以创建的类一起使用,假设这种类型可以转换(您可以定义它应该如何转换)到/从@987654326 @:

    trait Convertable[From, To] {
        def convert(from: From): To
    }
    
    object Convertable {
        implicit val intString = new Convertable[Int, String] {
            def convert(from: Int) = from toString // your logic here
        }
        
        implicit val stringInt = new Convertable[String, Int] {
            def convert(from: String) = from toInt // your logic here
        }
    
        implicit def self[T] = new Convertable[T, T] {
            def convert(from: T) = from
        }
    }
    
    case class Foo[T](original: T)(implicit toInt: Convertable[T, Int], fromInt: Convertable[Int, T]) {
        val x: Int = toInt convert original
        def toOriginal = fromInt convert x
    }
    
    
    println(Foo(512) x)
    println(Foo("256") x)
    

    (我可以通过返回 = original 来定义toOriginal,但这太无聊了:)

    如您所见,此解决方案是通用的且更复杂。但据我所知,许多应用程序需要在不同的原始值和/或类之间进行某种转换。因此,在许多情况下,它在许多情况下都是合适的(并且可能被认为是非常好的)解决方案,并且可能也适合您。但对于所有可能的情况,通常不可能说出什么是“最佳”解决方案。

    【讨论】:

    • 如果我们有另一个像def convetBackToString(i:Int)=i.toString 这样的静态方法,我们必须使用这个客户端代码来调用它:Foo.convertToString(Foo(110)) 有没有办法让它像Foo(110).convertToString 这样更简单?
    • @Esmaeilzadeh:有很多方法可以解决这个问题,但为了找到最好的方法,我需要了解更广泛的问题范围。最简单最直接的解决方案是 override def toString = convetBackToString(x) in class Foo
    • 它接缝了一个通用的解决方案是创建一些方法(在本例中为 toString ...)充当对象方法的代理并调用单例对象的方法,这是最好的解决方案吗?
    • @Esmaeilzadeh:我很难判断它是否是最佳解决方案,因为我不知道该解决方案试图解决的问题。抱歉,您提供的信息还不够。
    • 我建议使用 From => To 类型,而不是创建 Convertable 类型。如果您将此类函数类型声明为隐式,您还将在范围内自动进行许多此类隐式转换,例如Int => Long
    【解决方案2】:

    通过使用角度关于工厂方法而不是辅助构造函数的提议:

    class Foo(val s:String) {
          val s = ""
          def bar2:String = s+s
          def bar3:List[Char] = s.toList
    }
    
    object Foo extends{
          def bar1(y:List[Char]):String =y.mkString
          def apply(s:String)= new Foo(s)
          def apply(y:List[Char])= new Foo(bar1(y))
    }
    

    客户端代码:

    val foo1 = Foo(List('a','b'))
    println(foo1.s)
    println(foo1.bar2)
    println(foo1.bar3)
    

    【讨论】:

      【解决方案3】:

      您的解决方案还不错。毕竟convertToInt类似于Java中的静态方法。我个人不喜欢辅助构造函数,所以我通常也更喜欢 Easy Angels 解决方案。但是,如果您打算稍后从您的类继承,则伴随对象方法不会为派生类“扩展”,您将不得不重新实现该方法。在这种情况下,你应该坚持你的解决方案。

      理论上,您可以将该方法放在单独的特征中并对其进行扩展,但我不建议这样做。使用继承应仅限于存在真正依赖的情况,而不仅仅是为了“方便”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-28
        • 2019-01-10
        • 1970-01-01
        • 1970-01-01
        • 2015-07-28
        • 1970-01-01
        • 2019-04-10
        相关资源
        最近更新 更多