scala中对应python的__getattr__ / __setattr__。
在Scala中,没有直接等价于Python中的`__getattr__`和`__setattr__`的方法。这取决于你的用例,如果你只是想要一个动态类,Scala中将会有一个`Dynamic`特质;如果你只是想要其中一小部分功能,那么围绕模式匹配进行设计可能是一个明显的选择。
至于Python中的其他`__*__`方法,以下是它们在Scala中的等价方法:
全局方法:
- `__call__` → `apply()`,行为几乎相同
- `__metaclass__`,在Scala中使用取决于具体的用例:
- 目前,类继承或trait混入可能非常有用
- 在许多情况下,元类所做的全部工作就是实例构造,避免了对`super()`的调用;在Scala中,构造函数总是调用`super()`
- `__repr__`、`__str__` → `toString()`
- `__eq__` → `equals()`
- `__init__`,在类体中隐式调用
- `__new__`,直接不存在;根据用例的不同,可以使用早期初始化
- `__del__`,缺失
- `__nonzero__`,除了`implicit def toBool[MyType](a: MyType): Boolean = ...`之外并没有等价方法
容器类型:
- `__len__` → `length`、`size`或容器约定中的其他命名
- `__getitem__` → `apply(i: IndexType)`,在Scala中容器是函数
- `__setitem__` → `update(i: IndexType, v: ValueType)`
- `__delitem__`,不需要特殊处理,根据容器约定即可
- `__iter__` → `foreach(block: ValueType => Unit)`,带返回值的情况下可以使用`map`、`flatMap`
值得注意的是,在Scala中,`apply`和`update`与其Python对应方法一样是特殊的。它们允许以下语法:
val x = collection(elem) // val x = collection.apply(elem) collection(elem) = y // collection.update(elem, y)
类似地,就像Python的`__iter__`允许`for (el in container)`这样的语法一样,`foreach`和`map`使得`for (el <- container) yield el`成为可能。
运算符:
一般情况下,我们可以直接定义这些方法:
- `__add__`、`__sub__`等,只需定义`def + (arg: T)`或`def - (arg: T)`
- 包括比较运算符在内,例如`__lt__`、`__ge__`,可以定义`def <(other: T)`、`def <=(other: T)`
然而,就像Python一样,编译器对于一些高级事项有一些特殊情况:
- `__radd__`、`__rsub__`等,右结合的运算符,近似于`def +: (arg: T)`或`def -: (arg: T)`(在方法名后添加一个冒号)
- `__iadd__`、`__isub__`等,修改操作符:`def += (arg: T)`等
上下文管理器:
- `__enter__`、`__exit__`,在大多数情况下,可以使用函数参数来实现相同的目的
另外,可以参考Scala的“魔术”函数列表。但是除了`__getattr__`和`__setattr__`方法显然缺失之外,是否还有其他问题?