Член класса Scala Implicit недоступен в объекте

Я использую оболочку Scala bCrypt для шифрования пароля пользователя, эта оболочка предоставляет неявный класс.

package object bcrypt {

  implicit class Password(val pswrd: String) extends AnyVal {
    def bcrypt: String = B.hashpw(pswrd, BCrypt.gensalt())

    def bcrypt(rounds: Int): String = B.hashpw(pswrd, BCrypt.gensalt(rounds))

    def bcrypt(salt: String): String = B.hashpw(pswrd, salt)

    def isBcrypted(hash: String): Boolean = B.checkpw(pswrd, hash)
  }

  def generateSalt: String = B.gensalt()
}

Но я сталкиваюсь со странной проблемой: всякий раз, когда я использую это неявное преобразование в классе, оно работает нормально, но Converiosn не работает с объектными или тематическими классами.

scala> import com.github.t3hnar.bcrypt._
import com.github.t3hnar.bcrypt._

scala> class Password(secret: String) {
     |   def validate(userSecret: String): Boolean = userSecret.isBcrypted(secret)
     | 
     |   override def toString = secret
     | }
defined class Password

scala> object Password {
     |   def apply(secret: String): Password = new Password(secret)
     | 
     |   def getEncrypted(secret: String) = new Password(secret.bcrypt)
     | }
<console>:18: error: value bcrypt is not a member of String
         def getEncrypted(secret: String) = new Password(secret.bcrypt)
                                                                ^

scala> 

Я не уверен, что я делаю здесь не так.

1 ответ

Решение

Любые стабильные идентификаторы импортируются implicit идентификаторы. Вещи, которые могут скрыть последствия включают val, def, object и сгенерированный сопутствующий объект case class, просто classэс и types не создают идентификаторы и поэтому не импортируют тени implicit идентификаторы.

implicit class Password это просто синтаксический сахар для class Password и implicit def Passwordи так идентификатор в вашем коде с именем Password будет тень, что implicit def,

Итак, пока этот код компилируется нормально:

object Foo {
  import bcrypt._
  class Password()
  "123".bcrypt
}

Все следующие фрагменты не будут скомпилированы:

object Foo2 {
  import bcrypt._
  val Password = 1
  "123".bcrypt
}

object Foo3 {
  import bcrypt._
  def Password() = 1
  "123".bcrypt
}

object Foo4 {
  import bcrypt._
  case class Password()
  "123".bcrypt
}

object Foo5 {
  import bcrypt._
  object Password
  "123".bcrypt
}

Решение в вашем случае простое: переименуйте неявный класс в другое, что вряд ли будет конфликтовать с другими идентификаторами. Например, implicit class PasswordExtensions,

Если вы не можете переименовать implicit class в исходном коде вы можете импортировать его под другим именем: import com.github.t3hnar.bcrypt.{Password => PasswordExtensions, _}

Другие вопросы по тегам