Ne tür, nasıl kullanılacağını ve Dinamik iş yapar?
Dynamic ile bir şekilde mümkün Scala dinamik yazarak yapmak olduğunu duydum. Ama o gibi görünebilir nasıl olduğunu, nasıl çalıştığını hayal bile edemiyorum.
Tek özelliği Dynamic miras olduğunu öğrendim
class DynImpl extends Dynamic
API Bu gibi kullanabilir diyor ki:
foo.("") bla ~~>yöntem foo.("") yöntem ("") falan filan . applyDynamic
Ama denediğimde çalışmıyor:
scala> (new DynImpl).method("blah")
<console>:17: error: value applyDynamic is not a member of DynImpl
error after rewriting to new DynImpl().<applyDynamic: error>("method")
possible cause: maybe a wrong Dynamic method signature?
(new DynImpl).method("blah")
^
Bu sources, sonra bu özelliği tamamen boş olduğu ortaya çıktı, çünkü tamamen mantıklı. applyDynamic tanımlanmış ve kendi başıma nasıl hayal bile edemiyorum yöntem yoktur.
Birisi ne yapmam gerektiğini bana göster çalışması yapmak için?
CEVAP
Dynamic Scalas yazın ya da başka bir deyişle "dinamik dillerde." yöntem eksik bir kopyasıdır var olmayan nesneleri yöntemlerini çağırmak için izin verir
Doğrudur, scala.Dynamic herhangi bir üye yok, sadece işaretleyici bir arayüz - somut uygulama dolu derleyici tarafından. Scalas String Interpolation iyi tanımlanmış kurallar oluşturulan uygulama açıklayan bir özelliği vardır. Aslında, dört farklı yöntem uygulayabilirsiniz:
selectDynamic- alan set yazmak için izin verir:foo.barupdateDynamic- saha güncellemeleri yazmanıza olanak verir:foo.bar = 0applyDynamic- bağımsız değişkenleri ile yöntemlerini çağırmak için izin verir:foo.bar(0)applyDynamicNamedile yöntemlerini çağırmak için izin verir adlandırılmış bağımsız değişkenleri:foo.bar(f = 0)
Bu yöntemlerden birini kullanmak için Dynamic genişleten bir sınıf yazmak ve yöntemleri uygulamak için yeterli
class DynImpl extends Dynamic {
// method implementations here
}
Ayrıca eklemek gerek
import scala.language.dynamics
ya da derleyici seçeneği -language:dynamics özelliği varsayılan olarak gizli olduğu için ayarlayın.
selectDynamic
selectDynamic uygulamak için en kolay biridir. Derleyici bu yöntem bir bağımsız değişken listesi String bir bekliyor şartı aranır böylece foo.selectDynamic("bar") foo.bar bir ara bizimle iletişime geçiniz
class DynImpl extends Dynamic {
def selectDynamic(name: String) = name
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@6040af64
scala> d.foo
res37: String = foo
scala> d.bar
res38: String = bar
scala> d.selectDynamic("foo")
res54: String = foo
Gördügünüz gibi, aynı zamanda dinamik yöntemleri açık bir çağrı.
updateDynamic
updateDynamic *Bu yöntem 39* dönmek gerekiyor bir değeri güncelleştirmek için kullanılır çünkü. Ayrıca, alan adını güncellemeyi ve değeri derleyici tarafından farklı bağımsız değişken listesi geçti
class DynImpl extends Dynamic {
var map = Map.empty[String, Any]
def selectDynamic(name: String) =
map get name getOrElse sys.error("method not found")
def updateDynamic(name: String)(value: Any) {
map = name -> value
}
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@7711a38f
scala> d.foo
java.lang.RuntimeException: method not found
scala> d.foo = 10
d.foo: Any = 10
scala> d.foo
res56: Any = 10
Kod beklendiği gibi - olası kod çalışma zamanında eklemek için çalışıyor. Diğer tarafta, kod artık typesafe değil ve eğer bir yöntem çağrılırsa bu zamanı en iyi şekilde gerçekleştirilmelidir yok. Ayrıca bu kodu mümkün zamanında çağrılmalıdır yöntemleri oluşturmak için gerekli olan Dinamik dillerde kadar kullanışlı değil. Bu gibi bir şey yapamayız anlamına gelir
val name = "foo"
d.$name
d.$name zamanında d.foo dönüştürülmüş olacaktır. Ama bu bile dinamik dillerde bu tehlikeli bir özelliktir, çünkü o kadar da kötü değil.
Burada dikkate değer başka bir şey updateDynamic birlikte selectDynamic ile uygulanması gerekmektedir. Eğer bunu biz yapmazsak eğer aynı ada sahip bir Alıcı ise orada bir hata - bu kural sadece çalışan bir Pasör, uygulanması için benzer derleme alacağız.
applyDynamic
Argümanlarla yöntemlerini çağırmak için yeteneği applyDynamic tarafından sağlanır:
class DynImpl extends Dynamic {
def applyDynamic(name: String)(args: Any*) =
s"method '$name' called with arguments ${args.mkString("'", "', '", "'")}"
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@766bd19d
scala> d.ints(1, 2, 3)
res68: String = method 'ints' called with arguments '1', '2', '3'
scala> d.foo()
res69: String = method 'foo' called with arguments ''
scala> d.foo
<console>:19: error: value selectDynamic is not a member of DynImpl
Yöntemi ve bağımsız değişkenlerini daha farklı parametre listeleri için ayrılır. Eğer istersek argümanların rastgele bir sayı ile keyfi bir yöntem diyebiliriz ama eğer herhangi bir parantez olmadan bir yöntemi çağırmak istiyorsak selectDynamic uygulamamız gerekiyor.
Aynı zamanda applyDynamic ile geçerli sözdizimi kullanımı: . ipucu:
scala> d(5)
res1: String = method 'apply' called with arguments '5'
applyDynamicNamed
Son kullanılabilir yöntem bize eğer istersek bizim bağımsız değişken adı için izin verir:
class DynImpl extends Dynamic {
def applyDynamicNamed(name: String)(args: (String, Any)*) =
s"method '$name' called with arguments ${args.mkString("'", "', '", "'")}"
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@123810d1
scala> d.ints(i1 = 1, i2 = 2, 3)
res73: String = method 'ints' called with arguments '(i1,1)', '(i2,2)', '(,3)'
Yöntem imzası farkı applyDynamicNamed A keyfi bir türü olduğu 53 ** formun dizilerini bekliyor.
Yukarıdaki yöntemlerden tüm parametreleri belirlenmi ortak nokta şu:
class DynImpl extends Dynamic {
import reflect.runtime.universe._
def applyDynamic[A : TypeTag](name: String)(args: A*): A = name match {
case "sum" if typeOf[A] =:= typeOf[Int] =>
args.asInstanceOf[Seq[Int]].sum.asInstanceOf[A]
case "concat" if typeOf[A] =:= typeOf[String] =>
args.mkString.asInstanceOf[A]
}
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@5d98e533
scala> d.sum(1, 2, 3)
res0: Int = 6
scala> d.concat("a", "b", "c")
res1: String = abc
Neyse ki, aynı zamanda örtük değişkenler eklemek - eğer TypeTag bir bağlam bağlı eklersek kolayca bağımsız değişken türleri kontrol edebiliriz. Ve en iyi şey bile dönüş türü bazı atmalarını eklemek zorunda kalsak da doğrudur.
Ama Scala gibi kusurları etrafında bir yol bulmak için bir yol yoktur hiçbir zaman Scala olmaz. Bizim durumumuzda türü sınıflar yayınları: önlemek için kullanabiliriz
object DynTypes {
sealed abstract class DynType[A] {
def exec(as: A*): A
}
implicit object SumType extends DynType[Int] {
def exec(as: Int*): Int = as.sum
}
implicit object ConcatType extends DynType[String] {
def exec(as: String*): String = as.mkString
}
}
class DynImpl extends Dynamic {
import reflect.runtime.universe._
import DynTypes._
def applyDynamic[A : TypeTag : DynType](name: String)(args: A*): A = name match {
case "sum" if typeOf[A] =:= typeOf[Int] =>
implicitly[DynType[A]].exec(args: _*)
case "concat" if typeOf[A] =:= typeOf[String] =>
implicitly[DynType[A]].exec(args: _*)
}
}
Uygulama güzel görünmüyor olsa da, gücünü sorguladı olamaz:
scala> val d = new DynImpl
d: DynImpl = DynImpl@24a519a2
scala> d.sum(1, 2, 3)
res89: Int = 6
scala> d.concat("a", "b", "c")
res90: String = abc
Tüm üst kısmında, aynı zamanda makrolar Dynamic birleştirmek için:
class DynImpl extends Dynamic {
import language.experimental.macros
def applyDynamic[A](name: String)(args: A*): A = macro DynImpl.applyDynamic[A]
}
object DynImpl {
import reflect.macros.Context
import DynTypes._
def applyDynamic[A : c.WeakTypeTag](c: Context)(name: c.Expr[String])(args: c.Expr[A]*) = {
import c.universe._
val Literal(Constant(defName: String)) = name.tree
val res = defName match {
case "sum" if weakTypeOf[A] =:= weakTypeOf[Int] =>
val seq = args map(_.tree) map { case Literal(Constant(c: Int)) => c }
implicitly[DynType[Int]].exec(seq: _*)
case "concat" if weakTypeOf[A] =:= weakTypeOf[String] =>
val seq = args map(_.tree) map { case Literal(Constant(c: String)) => c }
implicitly[DynType[String]].exec(seq: _*)
case _ =>
val seq = args map(_.tree) map { case Literal(Constant(c)) => c }
c.abort(c.enclosingPosition, s"method '$defName' with args ${seq.mkString("'", "', '", "'")} doesn't exist")
}
c.Expr(Literal(Constant(res)))
}
}
scala> val d = new DynImpl
d: DynImpl = DynImpl@c487600
scala> d.sum(1, 2, 3)
res0: Int = 6
scala> d.concat("a", "b", "c")
res1: String = abc
scala> d.noexist("a", "b", "c")
<console>:11: error: method 'noexist' with args 'a', 'b', 'c' doesn't exist
d.noexist("a", "b", "c")
^
Makrolar zaman garanti derleme tüm geri ver ve yukarıdaki durumda yararlı olmasa da, belki biraz Dolaylı Scala için çok yararlı olabilir.
Eğer Dynamic hakkında daha fazla bilgi almak isterseniz biraz daha fazla kaynak vardır:
- Scala
Dynamicsunulan official SIP proposal - Practical uses of a Dynamic type in Scala - o zaman başka bir soru (ama çok eski

Nasıl iki JavaScript nesnelerin özelli...
Node.js / Express.js - Nasıl uygulamay...
Nasıl dinamik olarak değiştirmek angul...
Nasıl Emacs dosyaları yedekleme yapar ...
Nasıl @özelliğini dekoratör iş yapar?...