SORU
3 NİSAN 2013, ÇARŞAMBA


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
3 NİSAN 2013, ÇARŞAMBA


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.bar
  • updateDynamic - saha güncellemeleri yazmanıza olanak verir: foo.bar = 0
  • applyDynamic - bağımsız değişkenleri ile yöntemlerini çağırmak için izin verir: foo.bar(0)
  • applyDynamicNamed ile 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:

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Fraser Raft

    Fraser Raft

    9 Mart 2010
  • MrSuicideSheep

    MrSuicideShe

    9 NİSAN 2010
  • Santozz Yazz

    Santozz Yazz

    23 Mart 2014