Scala:哪个 类 不应该有伴生对象?
Scala: which classes should not have companion objects?
以下模式似乎是 scala 惯用的模式:
class Foo() {}
object Foo { def apply() = new Foo() }
val x = Foo()
采用惯用方法的动机是什么?在哪些情况下我应该不提供工厂方法,强制客户端使用val y = new Foo()
?所有带有伴随对象的案例都应该提供工厂方法吗?
如果满足以下条件 none,则 class 不需要伴随对象:
- class 中有一些功能未绑定到实例(在 Java 中称为 "static")
- 希望提供一个无需调用
new
的构造函数。这是通过 SomeClass.apply(params)
在 Scala 中完成的
如果对上述 none 感兴趣,则不需要伴随对象。
伴生对象是一种有用的结构——如果您有这些需要。如果没有,就没有理由拥有它。我不知道有什么理由绝对没有伴生对象。这是一个不需要的就不用写的工具。
Case class apply 通常被编译器重写为new。如果您编写自定义应用程序,即使是微不足道的应用程序,那也没有完成。
围绕隐式值 classes 可能存在类似的边缘情况。
$ scala
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> case class K(i: Int)
defined class K
scala> K(42)
res0: K = K(42)
scala> :javap -c res0
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
public static $line4.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line4/$read$$iw$$iw$
3: invokespecial #28 // Method "<init>":()V
6: return
public $line3.$read$$iw$$iw$K res0();
Code:
0: aload_0
1: getfield #31 // Field res0:L$line3/$read$$iw$$iw$K;
4: areturn
public $line4.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #33 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #35 // Field MODULE$:L$line4/$read$$iw$$iw$;
8: aload_0
9: new #14 // class $line3/$read$$iw$$iw$K
12: dup
13: bipush 42
15: invokespecial #38 // Method $line3/$read$$iw$$iw$K."<init>":(I)V
18: putfield #31 // Field res0:L$line3/$read$$iw$$iw$K;
21: return
}
scala> case class K(i: Int) ; object K { def apply(j: Int) = new K(j) }
defined class K
defined object K
scala> K(42)
res1: K = K(42)
scala> :javap -c res1
Compiled from "<console>"
public class $line6.$read$$iw$$iw$ {
public static $line6.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line6/$read$$iw$$iw$
3: invokespecial #31 // Method "<init>":()V
6: return
public $line5.$read$$iw$$iw$K res1();
Code:
0: aload_0
1: getfield #34 // Field res1:L$line5/$read$$iw$$iw$K;
4: areturn
public $line6.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #36 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #38 // Field MODULE$:L$line6/$read$$iw$$iw$;
8: aload_0
9: getstatic #41 // Field $line5/$read$$iw$$iw$K$.MODULE$:L$line5/$read$$iw$$iw$K$;
12: bipush 42
14: invokevirtual #45 // Method $line5/$read$$iw$$iw$K$.apply:(I)L$line5/$read$$iw$$iw$K;
17: putfield #34 // Field res1:L$line5/$read$$iw$$iw$K;
20: return
}
以下模式似乎是 scala 惯用的模式:
class Foo() {}
object Foo { def apply() = new Foo() }
val x = Foo()
采用惯用方法的动机是什么?在哪些情况下我应该不提供工厂方法,强制客户端使用val y = new Foo()
?所有带有伴随对象的案例都应该提供工厂方法吗?
如果满足以下条件 none,则 class 不需要伴随对象:
- class 中有一些功能未绑定到实例(在 Java 中称为 "static")
- 希望提供一个无需调用
new
的构造函数。这是通过SomeClass.apply(params)
在 Scala 中完成的
如果对上述 none 感兴趣,则不需要伴随对象。 伴生对象是一种有用的结构——如果您有这些需要。如果没有,就没有理由拥有它。我不知道有什么理由绝对没有伴生对象。这是一个不需要的就不用写的工具。
Case class apply 通常被编译器重写为new。如果您编写自定义应用程序,即使是微不足道的应用程序,那也没有完成。
围绕隐式值 classes 可能存在类似的边缘情况。
$ scala
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> case class K(i: Int)
defined class K
scala> K(42)
res0: K = K(42)
scala> :javap -c res0
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
public static $line4.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line4/$read$$iw$$iw$
3: invokespecial #28 // Method "<init>":()V
6: return
public $line3.$read$$iw$$iw$K res0();
Code:
0: aload_0
1: getfield #31 // Field res0:L$line3/$read$$iw$$iw$K;
4: areturn
public $line4.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #33 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #35 // Field MODULE$:L$line4/$read$$iw$$iw$;
8: aload_0
9: new #14 // class $line3/$read$$iw$$iw$K
12: dup
13: bipush 42
15: invokespecial #38 // Method $line3/$read$$iw$$iw$K."<init>":(I)V
18: putfield #31 // Field res0:L$line3/$read$$iw$$iw$K;
21: return
}
scala> case class K(i: Int) ; object K { def apply(j: Int) = new K(j) }
defined class K
defined object K
scala> K(42)
res1: K = K(42)
scala> :javap -c res1
Compiled from "<console>"
public class $line6.$read$$iw$$iw$ {
public static $line6.$read$$iw$$iw$ MODULE$;
public static {};
Code:
0: new #2 // class $line6/$read$$iw$$iw$
3: invokespecial #31 // Method "<init>":()V
6: return
public $line5.$read$$iw$$iw$K res1();
Code:
0: aload_0
1: getfield #34 // Field res1:L$line5/$read$$iw$$iw$K;
4: areturn
public $line6.$read$$iw$$iw$();
Code:
0: aload_0
1: invokespecial #36 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #38 // Field MODULE$:L$line6/$read$$iw$$iw$;
8: aload_0
9: getstatic #41 // Field $line5/$read$$iw$$iw$K$.MODULE$:L$line5/$read$$iw$$iw$K$;
12: bipush 42
14: invokevirtual #45 // Method $line5/$read$$iw$$iw$K$.apply:(I)L$line5/$read$$iw$$iw$K;
17: putfield #34 // Field res1:L$line5/$read$$iw$$iw$K;
20: return
}