在尝试包装任意对象时,我遇到了字典和列表的问题.调查,我设法提出了一段简单的代码,其行为我根本不理解.我希望你们中的一些人可以告诉我发生了什么:
>>> class Cl(object): # simple class that prints (and suppresses) each attribute lookup
... def __getattribute__(self, name):
... print 'Access:', name
...
>>> i = Cl() # instance of class
>>> i.test # test that __getattribute__ override works
Access: test
>>> i.__getitem__ # test that it works for special functions, too
Access: __getitem__
>>> i['foo'] # but why doesn't this work?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Cl' object has no attribute '__getitem__'
Run Code Online (Sandbox Code Playgroud) 有人可以告诉我为什么我在使用时获得不同的结果Tuple2[List,List]并且在下面的代码中List[List]作为我Product的?具体来说,我想知道为什么列表列表的第二个值被包装在另一个列表中?
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(4,5,6)
b: List[Int] = List(4, 5, 6)
scala> val c = List(a,b)
c: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> c.productIterator.foreach( println(_) )
List(1, 2, 3)
List(List(4, 5, 6)) // <-- Note this
scala> val d = (a,b)
d: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6))
scala> d.productIterator.foreach( println(_) )
List(1, 2, 3)
List(4, 5, …Run Code Online (Sandbox Code Playgroud) 任何精通Scala的人都可以解释为什么这样有效:
scala> Tuple2[String,String]("w3wre", "werffd")
res0: (String, String) = (w3wre,werffd)
scala> val (s1:Any, s2:Any) = Tuple2[String,String]("w3wre", "werffd")
s1: Any = w3wre
s2: Any = werffd
Run Code Online (Sandbox Code Playgroud)
但不是吗?
scala> Tuple2[String,String]("w3wre", null)
res1: (String, String) = (w3wre,null)
scala> val (s1:Any, s2:Any) = Tuple2[String,String]("w3wre", null)
scala.MatchError: (w3wre,null) (of class scala.Tuple2)
at .<init>(<console>:9)
at .<clinit>(<console>)
...
Run Code Online (Sandbox Code Playgroud)
(显然Any-type可以包含nulls:
scala> val n:Any = null
n: Any = null
scala> val n:Any = null.asInstanceOf[String]
n: Any = null
Run Code Online (Sandbox Code Playgroud)
)
?
我想知道是否有人有一个很好的干净Pythonic和有效的技术来实现在结果中涉及保护中相同表达的理解.需要说明的是,请考虑以下简单示例:
def f(a):
print "Calling", a
return a + 1
print [ f(v) for v in xrange(3) if f(v) > 1 ]
Run Code Online (Sandbox Code Playgroud)
这将打印
Calling 0
Calling 1
Calling 1
Calling 2
Calling 2
[2, 3]
Run Code Online (Sandbox Code Playgroud)
证明f对于大多数元素被调用两次.这很好,如果f有副作用,我们想要什么,但如果f是一些没有副作用的昂贵操作,重复调用是不可取的.但是对于每个元素只调用f一次的解决方案对我来说似乎笨拙/冗长:
intermediate = ( f(v) for v in xrange(3) )
print [ r for r in intermediate if r > 1 ]
Run Code Online (Sandbox Code Playgroud)
即使它被收缩成一条线
print [ r for r in ( f(v) for v in xrange(3) ) if r > 1 ]
Run Code Online (Sandbox Code Playgroud)
那么,任何人都能想出更好的东西吗?
我试图创建一个类型类,允许我在任何案例类上增加一个名为"counter"的Int字段,只要该类具有这样的字段.
我试图用Shapeless来做这件事,但是在击中墙壁之后(首先尝试消化"宇航员的无形指南",Shapeless 2.0.0的"功能概述"和Stack Overflow上的众多线程).
我想要的是能够做类似的事情
case class MyModel(name:String, counter:Int) {}
val instance = MyModel("Joe", 4)
val incremented = instance.increment()
assert(incremented == MyModel("Joe", 5))
Run Code Online (Sandbox Code Playgroud)
它适用于任何具有合适计数器字段的案例类.
我认为这可以使用类型类和Shapeless'记录抽象(以及隐式转换来获取作为方法添加的增量功能).裸骨将是这样的:
trait Incrementer[T] {
def inc(t:T): T
}
object Incrementer {
import shapeless._ ; import syntax.singleton._ ; import record._
implicit def getIncrementer[T](implicit generator: LabelledGeneric[T]): Incrementer[T] = new Incrementer[T] {
def inc(t:T) = {
val repr = generator.to(t)
generator.from(repr.replace('counter, repr.get('counter) + 1))
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这不编译.错误是value replace is not a member of generator.Repr.我想这是因为编译器没有任何保证T有一个被调用的字段counter而且它是类型 …
我有一段相当简单的代码无法编译,因为显然不能推断出类型。我想了解为什么它不起作用,因为我有很多类型注释,它应该可以工作。该代码是
object MyApp {
trait A {
type V
val value: V
}
case class ConcreteA(value: Int) extends A { type V=Int }
def convert[T<:A](v: T#V): T = ConcreteA(v.asInstanceOf[Int]).asInstanceOf[T] // brief method with casts for illustration purposes only
def main(args: Array[String]) {
val i: Int = 10
val converted: ConcreteA = convert(i)
}
}
Run Code Online (Sandbox Code Playgroud)
(如果我[ConcreteA]在convert-call 上添加了显式,它将进行编译)
我得到的错误是
MyApp.scala:19: error: no type parameters for method convert: (v: T#V)T exist so that it can be applied to arguments …Run Code Online (Sandbox Code Playgroud) 我开始在类型参数上使用抽象类型成员 - 主要是因为它们似乎对我的类型推断更好.但是,我仍然在努力理解如何从它们所定义的类型之外使用它们.例如,我无法理解为什么以下Scala程序不应该编译:
trait Thing
trait Describer {
type X<:Thing
def describe(x:X) = println(x)
}
object Program extends App {
def print[T <: Thing, D <: Describer]
(describer: D, thing:T)
(implicit ev: D#X =:= T)
= describer.describe(thing)
}
Run Code Online (Sandbox Code Playgroud)
直觉上,我希望这个要求D#X =:= T可以保证两种类型确实相等,因此两个实例可以互换使用,但是我得到了这个编译错误:
error: type mismatch;
found : thing.type (with underlying type T)
required: describer.X
= describer.describe(thing)
Run Code Online (Sandbox Code Playgroud)
我误解了什么?有没有其他方法可以做我想做的事情?或者失败,是否可以安全地thing转换为所需的类型(describer.X)?