5

我正处于学习 Scala 的早期阶段,我注意到声明方法的不同方式。

我已经确定不使用等号使该方法成为void方法(返回 aUnit而不是值),并且使用等号返回实际值,所以

def product(x: Int, y: Int) {
  x*y
}

将返回()(单位),但

def product(x: Int, y: Int) = {
  x*y
}

将返回两个参数的乘积(x*y

我注意到了第三种声明方法的方式——用冒号。这是一个例子

def isEqual(x: Any): Boolean

这与=符号有何不同?在什么情况下最好使用这种方式?

4

6 回答 6

12

当您使用冒号(并使用相等)时,您明确定义方法的返回类型。

// method return Boolean value
def m(a : Int) : Boolean = a > 0 

当您不使用冒号并使用 equal 时,您允许 scala 编译器推断返回类型本身。

// method has return type of last expression (Boolean)
def m(a : Int) = a > 0 

当您既不使用冒号也不使用等于时,您的方法的返回类型为 Unit 类。

// method has Unit return type
def m(a : Int){ 
    a > 0 
}
于 2014-10-31T08:14:39.500 回答
1

其他人已经完美地解释了不同声明之间的差异:

def foo: Boolean = true // explicitly declare the return type

def foo = true // let the compiler to implicitly infer Boolean

话虽如此,我不得不警告你

def foo { }

这称为过程语法,您永远不应该使用它,因为它已经被弃用(自 2013 年 10 月 29 日起),尽管您只会在-Xfuture标志下收到弃用警告。

每当您必须声明返回的方法时Unit(您应该尽可能避免,因为这意味着您依赖于副作用),请使用以下语法

def foo: Unit = { }

此外,作为个人建议,显式注释返回类型可以使您的代码通常更具可读性,并帮助您及早发现错误。您知道函数应该返回什么,因此显式注释类型允许编译器在声明位置检查实现是否返回适当的值(如果您使用该函数,您最终会捕获错误,但可能远离错误确实是)。

另外,在声明一个抽象成员时,最好也对类型进行注解

trait {
  def foo
}

是合法的,但类型foo会自动推断为Unit,这几乎不是您想要的。

相反,做

trait {
  def foo: Boolean
}
于 2014-10-31T08:58:22.917 回答
1

如果您不想要返回类型,那么您使用

scala> def product(x: Int, y: Int) { //in lack of = it explicit uses Unit 
     |   x*y
     | }
product: (x: Int, y: Int)Unit
//equivalent to below
scala> def product(x: Int, y: Int):Unit={ 
     |   x*y
     | }
product: (x: Int, y: Int)Unit

当你写

scala> def product(x: Int, y: Int) = {  //here it explicit detect return type
     |   x*y
     | }
product: (x: Int, y: Int)Int
//equivalent to below
scala> def product(x: Int, y: Int):Int = {
     |   return x*y
     | }
product: (x: Int, y: Int)Int
于 2014-10-31T08:24:53.200 回答
0

1) scala-2.11procedure syntax弃用,请避免使用。

def product(x: Int, y: Int) {
    x*y
}
// It always returns Unit. 
// creates confusion for most beginners. deprecated for good.

2)type inference语法,主要用于小型/私有方法。

def product(x: Int, y: Int) = {
    x*y
}

这是编译器的帮助,但有时编译器的推断可能与您的想法不同。

3)type annotation语法。

def product(x: Int, y: Int): Int = {
    x*y
}

对于公共 API,最好明确指定返回类型。

在某些情况下,必须指定返回类型。例如:

  • 定义递归方法时。

  • 当编译器的推断更具体但您需要通用返回类型(Map 代替 HashMap)时。

  • 覆盖编译器的推断。def getId(): Long = 1

  • 如果return在方法主体的任何地方使用。

于 2014-10-31T08:58:43.503 回答
0

在 Scala 中,函数定义为

def product(x: Int, y: Int): Int = {
  x*y
}

但是可以使用的“捷径”很少

  1. 由于 scala 具有良好的类型推断,您可以省略类型(除非函数是递归函数):

    def product(x: Int, y: Int) = { x*y }

  2. 一切都是一种表达。所以函数必须返回值。代码块的最后一行是返回值。所以如果你使用弯括号 {} 最后一行将被返回。如果函数只有一行,则不需要弯曲括号。

    def product(x: Int, y: Int) = x*y

  3. 由于一切都必须返回一个值,“无值”实际上是Unit. 因此,如果您不想返回有意义的值(这意味着您会产生一些副作用),请使用 Unit 作为返回值:

    def product(x: Int, y: Int): Unit = x*y

  4. 使用不带等号的函数只是返回 Unit 的另一种方式(这也称为“过程语法”:

    def product(x: Int, y: Int) { x*y }

于 2014-10-31T09:20:16.880 回答
0

def foo(arg) { sideEffects() }相当于def foo(arg) = { sideEffects(); Unit }。这是不好的风格,因为它隐藏了你的意图。(很容易忽略丢失的=)。我建议你不要使用它。

def foo(arg) = { expression }是一种隐式解析表达式类型的方法,风格很好。

def foo(arg): Type是具有显式类型的抽象方法定义。它不等同于其他两个示例,因为没有提供实现。

于 2014-10-31T08:45:08.760 回答