- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我知道我可以像这样添加动态“字段”:
import collection.mutable
class DynamicType extends Dynamic {
private val fields = mutable.Map.empty[String, Any].withDefault {key => throw new NoSuchFieldError(key)}
def selectDynamic(key: String) = fields(key)
def updateDynamic(key: String)(value: Any) = fields(key) = value
def applyDynamic(key: String)(args: Any*) = fields(key)
}
然后我可以做这样的事情:
val foo = new DynamicType
foo.age = 23
foo.name = "Rick"
但是,我想进一步扩展这一步骤并添加动态方法,例如:
foo.greet = (name: String) => s"Nice to meet you $name, my name is ${this.name}"
foo.greet("Nat"); //should return "Nice to meet you Nat, my name is Rick"
我尝试将所有方法存储在 updateDynamic
的单独映射中,但我无法找到处理 arity problem 的通用方法.那么有没有办法使用 Macros + Dynamics 来做这样的事情呢?
编辑:根据@Petr Pudlak 的回答,我尝试实现这样的东西:
import collection.mutable
import DynamicType._
/**
* An useful dynamic type that let's you add/delete fields and methods during runtime to a structure
*/
class DynamicType extends Dynamic {
private val fields = mutable.Map.empty[String, Any] withDefault { key => throw new NoSuchFieldError(key) }
private val methods = mutable.Map.empty[String, GenFn] withDefault { key => throw new NoSuchMethodError(key) }
def selectDynamic(key: String) = fields(key)
def updateDynamic(key: String)(value: Any) = value match {
case fn0: Function0[Any] => methods(key) = {case Seq() => fn0()}
case fn1: Function1[Any, Any] => methods(key) = fn1
case fn2: Function2[Any, Any, Any] => methods(key) = fn2
case _ => fields(key) = value
}
def applyDynamic(key: String)(args: Any*) = methods(key)(args)
/**
* Deletes a field (methods are fields too)
* @return the old field value
*/
def delete(key: String) = fields.remove(key)
//todo: export/print to json
}
object DynamicType {
import reflect.ClassTag
type GenFn = PartialFunction[Seq[Any],Any]
implicit def toGenFn1[A: ClassTag](f: (A) => Any): GenFn = { case Seq(a: A) => f(a) }
implicit def toGenFn2[A: ClassTag, B: ClassTag](f: (A, B) => Any): GenFn = { case Seq(a: A, b: B) => f(a, b) }
// todo: generalize to 22-args
}
1) 它可以正确处理字段与方法(甚至是 0-args),但非常冗长(目前最多只能使用 2 个 arg 方法)。有没有办法简化我的代码?
2) 无论如何支持动态方法重载(例如,添加 2 个具有不同签名的动态方法?)如果我可以获得函数的签名,我可以将其用作 methods
中的键> map 。
最佳答案
为了做到这一点,我们必须解决两个问题:
这是一种可能性:
首先,让我们定义最通用的函数类型:获取任意数量的任意参数并产生结果,如果参数的数量或类型不匹配,则失败:
type GenFn = PartialFunction[Seq[Any],Any]
现在我们创建一个动态类型,其中一切都是 GenFn
:
class DynamicType extends Dynamic {
import collection.mutable
private val fields =
mutable.Map.empty[String,GenFn]
.withDefault{ key => throw new NoSuchFieldError(key) }
def selectDynamic(key: String) = fields(key)
def updateDynamic(key: String)(value: GenFn) = fields(key) = value
def applyDynamic(key: String)(args: Any*) = fields(key)(args);
}
接下来,让我们创建隐式转换,将不同数量的函数转换为这种类型:
import scala.reflect.ClassTag
implicit def toGenFn0(f: => Any): GenFn =
{ case Seq() => f; }
implicit def toGenFn1[A: ClassTag](f: (A) => Any): GenFn =
{ case Seq(x1: A) => f(x1); }
implicit def toGenFn2[A: ClassTag,B: ClassTag](f: (A,B) => Any): GenFn =
{ case Seq(x1: A, x2: B) => f(x1, x2); }
// ... other arities ...
每次转换都会将一个函数(或一个值)转换为一个 GenFn
- 一个部分函数,如果给定的参数数量/类型错误,则该函数会失败。我们使用 ClassTag
以便能够匹配正确类型的参数。请注意,我们将值视为零参数的函数。这样我们处理 2. 的代价是通过在 name()
中给出零参数来使用检索值。
最后,我们可以这样做:
val foo = new DynamicType
foo.name = "Rick"
foo.greet = (name: String) =>
s"Nice to meet you $name, my name is ${foo.name()}"
println(foo.greet("Nat"));
为了支持方法重载,我们只需要链接PartialFunctions
。这可以实现为
def updateDynamic(key: String)(value: GenFn) =
fields.get(key) match {
case None => fields(key) = value
case Some(f) => fields(key) = f.orElse(value);
}
(请注意,它不是线程安全的)。然后我们可以调用类似的东西
val foo = new DynamicType
foo.name = "Rick"
foo.greet = (name: String)
=> s"Nice to meet you $name, my name is ${foo.name()}"
foo.greet = (firstName: String, surname: String)
=> s"Nice to meet you $firstName $surname, my name is ${foo.name()}"
println(foo.greet("Nat"));
println(foo.greet("Nat Smith"));
请注意,此解决方案的工作方式与标准方法重载略有不同。这取决于添加功能的顺序。如果先添加更通用的函数,则永远不会调用更具体的函数。所以总是先添加更具体的功能。
你这样做可能会更困难,因为你似乎不区分函数的类型(就像我的 toGenFn...
方法一样),所以如果函数得到错误的参数,它只会抛出一个异常而不是将它们传递给下一行。但它应该适用于具有不同数量参数的函数。
我认为不可能避免检查各种参数的函数所导致的冗长,但我认为这并不重要。这只是一次性工作,DynamicType
的客户端不受它的影响。
关于斯卡拉动力学 : Ability to add dynamic methods?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18557183/
我是 KineticJS 的新手,我正在尝试弄清楚如何使用按钮使不同的项目出现或消失。下面是带有示例的 JSFiddles。 有四个盒子。我想这样做,以便当我单击一个框的按钮时,该框出现并且任何其他可
我正在尝试使用 KineticJS 设置 Sprite 动画,当我将鼠标悬停在该 Sprite 上时,移动到另一个动画并停止它。 var stage = new Kinetic.Stage({
例如:轻按一下即可移动形状。另一个点击是同时移动另一个形状。 最佳答案 我分享了我在 Kinetic + Multi Touch 上做的一个小实验 here .看看 - 在 Kinetic 中提供“真
首先,由于最新版本中的组拖动(已知)错误,我需要使用 kinetic-v4.3.3 版本。 所以我有一个动力学结构如下: ShapesGroup ShapeGroup Circle T
我有这个 fiddle : http://jsfiddle.net/WDjpx/2/ 图像旋转不正确。我使用的代码是: var stage = new Kinetic.Stage({ cont
是的,我知道它不应该被滥用,并且 C# 主要用作静态语言。但是说真的,伙计们,如果你可以用 python 风格弄脏一些代码,或者创建一些动态的 do hicky,你愿意吗? 我一直在加类加点地研究这个
如何为组中的每个 Kinetic.Rect 创建点击事件? 假设我有这个: var bar1 = new Kinetic.Rect({ x: 0, y: 100,
我正在尝试制作一个平移和缩放 Canvas 以用作游戏中的迷你 map 。我已将舞台设置为可拖动,以便玩家可以使用鼠标四处移动,以及移动舞台图层上的单个对象。但是,我不希望能够将舞台拖到周围的白色空间
我阅读了有关可拖动边界的内容,并希望将其设置为与 Canvas 相同的大小(因为图像在边缘超出了站点范围,这可能吗? 最佳答案 var image = new Kinetic.Image({
目前我正在尝试使用 Kinetic JS,示例如下: http://jsfiddle.net/r8rtJ/4/ var yoda = new Kinetic.Image({ x: 0,
我是一名优秀的程序员,十分优秀!