Как написать & # 8220; asInstanceOfOption & # 8221; в Скале

StackOverflow https://stackoverflow.com/questions/1803036

  •  05-07-2019
  •  | 
  •  

Вопрос

Можно ли написать "asInstanceOfOption"? метод, который будет делать то, что задумано следующим (поддельным) кодом?

def asInstanceOfOption[T](o: Any): Option[T] =
   if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None 
Это было полезно?

Решение

РЕДАКТИРОВАТЬ Ниже приведен мой оригинальный ответ, но вы можете сделать это сейчас с помощью

def asInstanceOfOption[T: ClassTag](o: Any): Option[T] = 
  Some(o) collect { case m: T => m}
<Ч>

Вы можете использовать манифесты, чтобы обойти тот факт, что тип T стирается во время компиляции:

scala> import scala.reflect._
import scala.reflect._

scala> def asInstanceOfOption[B](x : Any)(implicit m: Manifest[B]) : Option[B] = {
   | if (Manifest.singleType(x) <:< m)
   |   Some(x.asInstanceOf[B])
   | else
   |   None
   | }
asInstanceOfOption: [B](x: Any)(implicit m: scala.reflect.Manifest[B])Option[B]

Тогда это можно использовать:

scala> asInstanceOfOption[Int]("Hello")
res1: Option[Int] = None

scala> asInstanceOfOption[String]("World")
res2: Option[String] = Some(World)

Вы даже можете использовать неявные преобразования , чтобы этот метод был доступен для Any . Я думаю, что предпочитаю имя метода matchInstance :

implicit def any2optionable(x : Any) = new { //structural type
  def matchInstance[B](implicit m: Manifest[B]) : Option[B] = {
    if (Manifest.singleType(x) <:< m)
      Some(x.asInstanceOf[B])
    else
      None
  }   
}

Теперь вы можете написать код вроде:

"Hello".matchInstance[String] == Some("Hello") //true
"World".matchInstance[Int] == None             //true    

РЕДАКТИРОВАТЬ: обновленный код для 2.9.x, где нельзя использовать Any , но только AnyRef :

implicit def any2optionable(x : AnyRef) = new { //structural type
  def matchInstance[B](implicit m: Manifest[B]) : Option[B] = {
    if (Manifest.singleType(x) <:< m)
      Some(x.asInstanceOf[B])
    else
      None
  }   
}

Другие советы

Вот подробное описание обновленного ответа oxbow_lake, дополнительно обновленного до версии Scala 2.10:

// Implicit value class
implicit class Castable(val obj: AnyRef) extends AnyVal {
  def asInstanceOfOpt[T <: AnyRef : ClassTag] = {
    obj match {
      case t: T => Some(t)
      case _ => None
    }
  }
}

Это можно использовать, выполнив:

"Hello".asInstanceOfOpt[String] == Some("Hello") // true
"foo".asInstanceOfOpt[List[_]] == None // true

Однако, как уже упоминалось в других ответах, это не работает для примитивов из-за проблем с боксом и не обрабатывает дженерики из-за стирания. Чтобы запретить примитивы, я ограничил obj и T расширением AnyRef . Для решения, которое обрабатывает примитивы, обратитесь к ответу на дополнительный вопрос Мэтта Р.:

Как написать asInstanceOfOpt [T] где T < ;: Any

Или используйте бесформенный Typeable, который обрабатывает примитивы, а также многие случаи стирания:

Приведение типов с использованием параметра типа

На момент написания ответа oxbow_lakes (в конце '09) я считаю, что scala.util.Try не был доступен, однако, сейчас (т. е. по состоянию на 2.10) я думаю, что scala.util.Try - это предпочтительный (или, по крайней мере, более приятный) способ сделать это:

scala> Try((3).asInstanceOf[String]).toOption
res0: Option[String] = None

scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top