Как я могу сделать динамическое приведение переменной из одного типа в другой в Scala - PullRequest
0 голосов
/ 14 января 2019

Я хотел бы выполнить динамическое приведение для переменной scala, тип преобразования хранится в другой переменной или в базе данных или предоставлен пользователем.

Я новичок в Scala и в основном занимался программированием на python. Здесь мы пытаемся взять любой тип ввода и запросить тип переменной в соответствии с типом, сохраненным в БД, например: «String / Int» и определяемые пользователем классы, и привести их перед любой последующей обработкой.

в питоне:

eval("str('123')")

в скале я пробовал

var a = 123.05
a.asInstanceOf['Int']

дает мне ошибку

ошибка: идентификатор ожидается, но найден строковый литерал.

И я хочу, чтобы код был следующим:

var a = 123.05
var b = "Int"
a.asInstanceOf[b]

дает мне ошибку

ошибка: не найдено: введите b

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Хорошо, поэтому я должен быть довольно исчерпывающим, потому что вы пытаетесь сделать что-то хитрое из-за разницы между статической и динамической типизацией scala и python.

Первое, что вы делаете в Python, это не приведение типов, а преобразование.

str(12)

в python принимает целое значение 12 и преобразует его в строку (UTF-8? Не знаю в python). То же самое в скале будет

12.toString

Тем временем приведение типов - это в основном мизерное обещание для проверки типов компиляторов, что вы знаете больше, чем он, и он должен просто вам верить. Этого также следует избегать, как вредителя, потому что вы в основном отбрасываете всю безопасность, которую дает вам статическая проверка типов. Однако есть определенные случаи, когда это неизбежно

в несколько более фундаментальных терминах. Допустим, у вас есть следующий фрагмент scala

sealed trait Foo
final case class Bar(i:Int) extends Foo
final case class Baz(s:String) extends Foo

val f:Foo = Bar(2)
//won't work because the compiler thinks f is of type Foo due to the type ascription bove
println(f.i)
//will work
println(f.asInstanceOf[Bar].i)

Тип Foo может быть либо Bar, либо Baz (из-за закрытого и конечного, это называется ADT), но мы специально указали компилятору трактовать f как Foo, что означает, что мы забыли, какой специфический типа это было. это тот случай, когда вы можете использовать приведение типов, обратите внимание, что мы не конвертируем, а скорее сообщаем компилятору, что это на самом деле Bar

Теперь все это происходит во время компиляции, что означает, что вы не можете кастовать в соответствии со значением времени выполнения, как это

var a = 123.05
var b = "Int"
a.asInstanceOf[b]

Теперь, насколько я понимаю, у вас есть какой-то строковый тип ввода и вам нужно преобразовать его в соответствии с какой-то схемой. Ниже приведен пример того, как вы можете это сделать: https://scalafiddle.io/sf/i97WZlA/0

Однако обратите внимание, что здесь используются некоторые довольно продвинутые концепции в scala для обеспечения согласованности типов.

Это также будет работать https://scalafiddle.io/sf/i97WZlA/1, но учтите, что мы теряем всю информацию о типах, требующую от нас выполнения тип-трансляции, если мы хотим сделать что-либо значимое с out

EDIT / ADDENDUM: Я подумал, что мне следует также сделать пример того, как использовать такие значения и сделать схему динамической.

https://scalafiddle.io/sf/i97WZlA/2

В качестве заключительного замечания предупреждаем, что это приближается к пределам, которые может делать компилятор, и требует большого количества коробок и распаковок для переноса информации о типе (в SchemaValue), а также не является безопасным для работы со стеком и имеет слабую обработку ошибок , это решение потребует серьезной разработки, чтобы сделать его жизнеспособным, но оно должно охватить идею

0 голосов
/ 14 января 2019

Если у вас есть значение String, вы можете использовать toInt или toDouble для анализа этой строки:

val s = "123.05"
val i = s.toInt
val d = s.toDouble

Если у вас есть значение Any, то лучше использовать match для его преобразования:

val a: Any = ...

a match {
  case i: Int => // It is an Int
  case d: Double => // It is a Double
  case _ => // It is a different type
}

Если ничего не помогает, вы можете явно выбрать тип, но это не очень хорошая практика:

val i = a.asInstanceOf[Int]

Любая приличная структура базы данных даст вам возможность читать и записывать значения определенных типов, поэтому это не должно быть проблемой с правильной библиотекой.

...