【问题标题】:Scala private apply method?Scala私有应用方法?
【发布时间】:2019-01-18 07:32:49
【问题描述】:

我目前正在制作一个可以存储英语单词的类。我想让它尽可能安全(如果输入无效 - 返回错误消息),这就是我迷路的地方。我有这个存储英文单词的代码:

  case class English_LT_Word private (word: String)
  object English_LT_Word {
    def apply(word: String) = new English_LT_Word(word)
    def createNewWord(word: String): Either[String, English_LT_Word] = {
      if (word.length > 0 && word.forall(x=>consonants.contains(x) || vowels.contains(x))) Right(apply(word))
      else Left("'" + word + "'" + " is an invalid word")
    }
  }

在这个例子中,我可以像这样创建任何英文单词:

val english = English_LT_Word.apply("Awesome")
val english = English_LT_Word.createNewWord("Awesome")

在这里,我对使用什么有一个难题,它并不漂亮。我该如何正确地做到这一点?将 .apply() 方法设为私有是不可能的,因为(长话短说)编译器将不同步。我希望只能使用 .createNewWord() 方法来创建我的单词。有什么想法吗?

谢谢!! ^^

【问题讨论】:

    标签: scala methods apply private


    【解决方案1】:

    创建一个带有伴生对象的简单类,该类可以创建EnglishWord的正确实例

    必须使用伴随对象创建实例。如果直接使用new关键字创建实例,编译器不允许

    class EnglishWord private (word: String)
    
    object EnglishWord {
    
     def createEnglishWord(word: String): Either[String, EnglishWord] = {
    
      if (word.length > 0 &&
        word.forall(x => consonants.contains(x) || vowels.contains(x)))
        Right(new EnglishWord(word))
      else Left("'" + word + "'" + " is an invalid word")
    
     }
    
    }
    

    【讨论】:

    • 我从来不明白这一点。如果您使用val w = EnglishWord(...),则 w 是 Either 不是英文单词。我没有任何其他建议,但这让我觉得这是一个令人困惑的 API。我认为如果我们不返回相应类的实例,我们不应该使用 apply
    • 在 Scala 中使用“代数类型”(如 Either 和 Option)是非常标准的做法。熟悉它们很好;它们非常有用,一旦您了解它们,我就会发现它们是该语言的最佳功能之一。考虑在这里使用 Either 而不是在 Java 中使用 try/catch。
    • @Metropolis 我同意 Option 和 Either。我没有得到的是说= A() 并得到Either[_, A]。这是一个 API 问题,而不是一个 Either & Option 问题
    【解决方案2】:

    我会做几乎你已经在做的事情,但没有应用......

    class English_LT_Word private (word: String)
    
    object English_LT_Word {
      def create(word: String): Either[String, English_LT_Word] = {
        if (word.length > 0 && word.forall(x=>consonants.contains(x) || vowels.contains(x)))
          Right(new English_LT_Word(word))
        else
          Left("'" + word + "'" + " is an invalid word")
      }
    }
    

    或者你可以模仿一些集合 API,例如头选项

    object English_LT_Word {
      private def isValidWord(s: String) = !s.isEmpty && s.toLowerCase.forall(('a' to 'z').contains)
    
      def createOption(word: String): Option[English_LT_Word] = {
        if isValidWord(word) Some(new English_LT_Word(word)) else None
      }
    }
    

    那么行为就很清楚了(我冒昧地调整了验证,如果你愿意,请忽略)

    【讨论】:

      【解决方案3】:

      您可以使用-Xsource:2.12 在 2.12 或 2.11 下定义您的自定义案例伴侣应用。

      $ ~/scala-2.11.12/bin/scala -Xsource:2.12 
      cat: /usr/lib/jvm/jdk1.8.0/release: No such file or directory
      Welcome to Scala 2.11.12 (OpenJDK 64-Bit Server VM, Java 1.8.0_181).
      Type in expressions for evaluation. Or try :help.
      
      scala> :pa
      // Entering paste mode (ctrl-D to finish)
      
      import scala.util._
      
      case class Word private (text: String)
      object Word {
        def apply(s: String): Either[String, Word] =
          if (s.nonEmpty) Right(new Word(s)) else Left("Empty word!")
      }
      
      // Exiting paste mode, now interpreting.
      
      import scala.util._
      defined class Word
      defined object Word
      
      scala> Word("")
      res0: scala.util.Either[String,Word] = Left(Empty word!)
      
      scala> Word("ok")
      res1: scala.util.Either[String,Word] = Right(Word(ok))
      

      【讨论】:

      • 申请案例类需要new吗?
      • @JoelBerkeley 我只是表明他们可以编写您自己的申请,取代合成申请。所以这里需要用到构造函数。 C(x) 在类型检查后被重写为 new C(x)
      猜你喜欢
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 1970-01-01
      • 2013-01-20
      • 1970-01-01
      • 2018-05-03
      • 1970-01-01
      相关资源
      最近更新 更多