我刚开始学习Scala。我对OO设计很满意,而功能编程却不那么简单;虽然,我编程的时间足够长,FP对我来说也不是完全不自然。从我斯卡拉冒险的第一天开始,我就已经说过了,对OO和FP之间正在发生的明显辩证法感到不安。显然,人们可以一路走来。我的第一个倾向是将类看作是一种包含我想要传递的功能的包,这平衡了功能方面的尺度。我觉得必须有一种更好的方法来平衡这种行为。在这种情况下,我也不确定如何处理某些熟悉的情况。例如,如果我有以下(人工)类:
class ValueGenerator {
def value() = {
"1"
}
def value(line: String) = {
line
}
}
在OO编程中,我会在需要时用适当的签名调用value
,以获得我需要的结果。这些方法具有相同的签名,因为它们在逻辑上对应于类似的操作。在OO中,我会传递对象引用,并且接收ValueGenerator
对象的方法将根据情况调用右value
。据我所知,至少我的倾向是,在Scala中,规范是传递方法。但在这种情况下,虽然方法做同样的事情,但它们没有相同的签名,因此不能互相替换(或者它们可以吗?)。换句话说,无论函数的签名如何,发送方方法都能决定要发送的函数吗?这似乎不太可能,因为接收器不知道如何调用它。在这种情况下,正确的行动是什么。或者一个人的直觉本能?在谈到OO和FB时,你会遵循一条经验法则吗?
作为旁注,很有意思的是,我的一位正在学习Scala的朋友在这个问题上有与我的确切想法(或缺乏)。
答案 0 :(得分:9)
它们没有相同的签名,通常您希望不具有相同签名的方法具有不同的名称。重载很少,并且会花费很多(即类型推断和隐式解析)。
那就是说,他们不能互相替代,因为他们没有相同的类型。如果要将这些方法转换为函数,则可以使用类型Function0[String]
,另一个类型为Function1[String, String]
。
答案 1 :(得分:4)
在您提供的代码中,您没有理由需要两个单独的方法签名:
class ValueGenerator {
def value(line: String = "1") = {
line
}
}
REPL会议:
scala> new ValueGenerator()
res1: ValueGenerator = ValueGenerator@fa88fb
scala> res1.value("Foo")
res2: String = Foo
scala> res1.value()
res3: String = 1
请记住,您只能使用方法执行此操作。函数不支持默认参数:
scala> val f = res1.value(_)
f: (String) => String = <function1>
scala> f("Bar")
res5: String = Bar
scala> f()
***Oops***
scala> val f = (line: String) => line
f: (String) => String = <function1>
scala> val f = (line: String = "1") => line
***Oops***
答案 2 :(得分:2)
据我所知,至少我的倾向是,在Scala中,规范是传递方法。
我怀疑这是常态(你为什么这么认为?)或者Scala中甚至有这样的规范。
但在这种情况下,虽然方法做同样的事情,但它们没有相同的签名,因此不能互相替换(或者它们可以吗?)。换句话说,无论函数的签名如何,发送方方法都可以决定要发送的函数吗?
它们不能互相替代,因为它们具有不同的签名,因此它们具有不同的类型。
您描述的场景听起来非常适合OO操作方式:只需传递ValueGenerator
对象,让客户端决定在该对象中调用哪个方法。