我看到Scala中的特性与Java中的接口类似(但Java中的接口扩展了其他接口,它们不扩展类).我在SO上看到了一个关于特征使用的例子,其中特征扩展了一个类.
这样做的目的是什么?为什么traits可以扩展类?
快速说明:Scala for Java Refugees第5部分:特征和类型教程中的示例.
假设我有学生,工人,薪水不足和年轻的特征.
我如何声明具有所有这些特征的类(不是实例),CollegeStudent?
注意:我知道简单的案例,例如具有一个或两个特征的CollegeStudent:
class CollegeStudent extends Student with Worker
Run Code Online (Sandbox Code Playgroud) 我正在使用laravel 5,我对在laravel 5目录结构中放置traits文件的位置感到困惑.它们是否应该存在于公共,资源或任何其他目录中?
我知道这个功能在C#中不存在,但PHP最近添加了一个名为Traits的功能,我认为这个功能起初有点傻,直到我开始考虑它.
假设我有一个名为的基类Client
.Client
有一个叫做的属性Name
.
现在我正在开发一个可供许多不同客户使用的可重用应用程序.所有客户都同意客户应该有一个名字,因此它属于基类.
现在客户A出现并表示他还需要跟踪客户的权重.客户B不需要重量,但他想跟踪高度.客户C想要跟踪重量和高度.
有了特征,我们可以制作权重和高度特征:
class ClientA extends Client use TClientWeight
class ClientB extends Client use TClientHeight
class ClientC extends Client use TClientWeight, TClientHeight
Run Code Online (Sandbox Code Playgroud)
现在,我可以满足所有客户的需求,而无需在课堂上添加任何额外的毛病.如果我的客户稍后回来并说"哦,我真的很喜欢这个功能,我也可以拥有它吗?",我只是更新了类定义以包含额外的特性.
你会如何在C#中实现这一目标?
接口在这里不起作用,因为我想要对属性和任何相关方法的具体定义,我不想为每个版本的类重新实现它们.
("客户",我指的是雇用我作为开发人员的文字人员,而"客户"我指的是编程课程;我的每个客户都有他们想要记录信息的客户)
c# code-reuse design-patterns traits default-interface-member
鉴于一个特点MyTrait
:
trait MyTrait {
def doSomething = println("boo")
}
Run Code Online (Sandbox Code Playgroud)
它可以与extends
or 混合成一个类with
:
class MyClass extends MyTrait
Run Code Online (Sandbox Code Playgroud)
它也可以在实例化一个新实例时混合:
var o = new MyOtherClass with MyTrait
o.doSomething
Run Code Online (Sandbox Code Playgroud)
但是......可以将特征(或任何其他如果产生影响的特征)添加到现有实例中吗?
我在Java中使用JPA加载对象,我想使用traits为它们添加一些功能.有可能吗?
我希望能够按如下方式混合特征:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
Run Code Online (Sandbox Code Playgroud) 我想使用现有的功能trait
并trait
在其上创建我自己的功能,只是稍后将其应用于类.
确切地说,我想扩展Laravel SoftDeletes
trait来制作SaveWithHistory
函数,因此它会创建一个记录当前状态的副本作为已删除的记录.我也想用record_made_by_user_id
字段来扩展它.
如果我理解正确,traits是最接近Java接口的东西,类构造函数会自动设置变量.
但是如果我有一个扩展特征的类并且有一个构造函数来设置变量的特性,那么会是这样的:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
我想要的地方foo
当我制作一个Bar
物体时,就设置了这个特征的字符串.
编译器似乎给我错误.实现这一目标的正确方法是什么?
在Scala中,我已经看到了这些结构
trait T extends S
Run Code Online (Sandbox Code Playgroud)
和
trait T { this: S =>
Run Code Online (Sandbox Code Playgroud)
用于实现类似的东西(即S
必须在创建实例之前定义抽象方法).他们之间有什么区别?你为什么要用另一个呢?
我做了一个两元素Vector
结构,我想重载+
运算符.
我使我的所有函数和方法都采用引用而不是值,我希望+
运算符以相同的方式工作.
impl Add for Vector {
fn add(&self, other: &Vector) -> Vector {
Vector {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据我尝试的变化,我要么遇到生命问题,要么输入不匹配.具体来说,这个&self
论点似乎没有被视为正确的类型.
我已经看到了模板参数的例子上impl
,以及Add
,但他们只是导致不同的错误.
我发现如何为不同的RHS类型和返回值重载运算符?但即使我把一个use std::ops::Mul;
放在顶部,答案中的代码也不起作用.
我正在使用rustc 1.0.0-nightly(ed530d7a3 2015-01-16 22:41:16 +0000)
我不接受"你只有两个字段,为什么要使用参考"作为答案; 如果我想要一个100元素结构怎么办?我会接受一个答案,证明即使有一个大的结构我也应该通过值传递,如果是这样的话(我认为不是这样).我有兴趣知道结构大小的一个好的经验法则并且通过值vs struct传递,但这不是当前的问题.
使用特征时,我很难理解Scala中的线性化顺序:
class A {
def foo() = "A"
}
trait B extends A {
override def foo() = "B" + super.foo()
}
trait C extends B {
override def foo() = "C" + super.foo()
}
trait D extends A {
override def foo() = "D" + super.foo()
}
object LinearizationPlayground {
def main(args: Array[String]) {
var d = new A with D with C with B;
println(d.foo) // CBDA????
}
}
Run Code Online (Sandbox Code Playgroud)
它打印CBDA
但我无法弄清楚为什么.如何确定特征的顺序?
谢谢
traits ×10
scala ×6
php ×2
c# ×1
code-reuse ×1
composition ×1
constructor ×1
laravel ×1
laravel-5 ×1
lifetime ×1
mixins ×1
php-7 ×1
reference ×1
rust ×1
self-type ×1