剖析 scala 中的简单函数声明
这个例子来自Beginning Scala,但对我来说解释得不够好。
val f: Int => String = x => "Dude: "+x
我确实有两个问题:
1)第一个示例是否与下面的代码相同:
val f = (x:Int) => "Dude: "+x
2)如果是的话,有人可以详细说明,并稍微剖析第一个示例。 String = x 部分让我失望。我不知道如何阅读该声明
This example is from Beginning Scala, but it isn't really explained well enough for me.
val f: Int => String = x => "Dude: "+x
I have 2 questions really:
1) Is the first example identical to the code below:
val f = (x:Int) => "Dude: "+x
2) If so can someone elaborate, and dissect the first example a little bit. the String = x part throws me off. I'm not sure how to read the statement
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
他们是一样的。您可以通过两种不同的方式让 scala 的类型推断为您工作。
在 val f: Int => 中字符串 = x => "Dude: "+x = 号之前的部分是您显式声明
f
类型Int =>; 的地方String
(即您说 f 是一个接受 Int 类型输入并返回 String 的函数)在 = 的右侧,您将给 f 赋值。该值(根据您的声明)必须是一个接受 Int 并返回 String 的函数。
事实上,你是说 f 等于 x => “伙计:”+x。
scala 编译器的类型推断在这里为您工作,因为它知道 x 必须是 Int,因为您已将 f 声明为从 Int 到 String 的函数。
在 val f = (x:Int) => 中“老兄:”+x 你让 scala 的类型推断通过查看你分配给它的值来“猜测” f 的类型是什么。这个值(在=的右侧)是一个函数,它接受一个Int(因为你明确地说了
x:Int
)并返回一个String(因为你将x添加到“Dude:”,这是一个字符串,因此 string + x 的结果必须是字符串本身)。注意:如果您在 REPL 中尝试这两个版本,您会注意到在一种情况下您将 f 定义为 (Int) =>字符串,在其他中为 (Int) => java.lang.String
它们(从 scala 2.8.1 开始)是相同的:scala 的 String 定义(在 Predef.scala 中)只是
type String = java.lang.String
。这可能是针对针对 .NET 框架的 scala 版本所做的(其中 String 可能是 .NET 的 System.String 的别名),以便您始终可以在 scala 程序中编写 String。They are the same. You are making scala's type inference work for you in two different ways.
In
val f: Int => String = x => "Dude: "+x
the part before the = sign is where you explicitly declaref
of typeInt => String
(i.e. you're saying that f is a function that takes an input of type Int and returns a String)On the right side of the = you're assigning a value to f. The value (according to your declaration) must be a function that takes an Int and returns a String.
In fact you are saying that f is equal to
x => "Dude: "+x
.The scala compiler's type inference is working for you, here, because it understands that x must be an Int from the fact you have declared f as a function from Int to String.
In
val f = (x:Int) => "Dude: "+x
you're letting scala's type inference "guess" what the type of f is by looking at the value you assign to it. This value (on the right side of the =) is a function that takes an Int (because you explicitly say thatx:Int
) and returns a String (because you add x to "Dude: ", which is a string, so the result of string + x must be a string itself).Note: if you try the two versions in the REPL, you'll notice that in one case you will have f defined as (Int) => String, in the other as (Int) => java.lang.String
They are (as of scala 2.8.1) the same thing: scala's String definition (in Predef.scala) is simply
type String = java.lang.String
. This was probably done for the version of scala that targeted the .NET framework (where String was likely an alias for .NET's System.String) so that you could always write String in your scala programs.好吧,我们开始吧:
读取为函数声明为带有签名的值,该签名将第一个输入值从
Int
类型映射到String 类型的输出值
。使用 lambda(或函数文字)读取为函数定义,该函数采用名为 x 的参数,将其附加到字符串
“Dude:”
并返回它。该定义被分配给值f
。由于值f
是用Int => 声明的。当编译器推断其类型时,String
、x
将采用Int
类型。在 Scala 中,函数体的最后一个表达式是 return 语句,在本例中它也恰好是一个String
,这符合我们的声明。另外,在Java和Scala中,运算符+
是重载的。当您尝试将String
添加到Int
时,结果将是字符串值和整数的字符串连接。现在检查一下:
这一次,
f
没有用类型声明,它的类型是从它的定义中推断出来的(x:Int) =>; "Dude: " + x
,这是一个函数文字,它采用Int
类型的名为x
的参数并返回String
。应该清楚的是,这两个版本现在是等效的。现在作为练习,尝试编写更多使用关键字
def
的版本。完成后,在 REPL 中键入所有这些f()
并观察它们的签名。到那时应该就清楚了。Ok here we go:
reads as a function declared as a value with a signature that maps the first input value from a type
Int
to an output value of typeString
.reads as a function definition using a lambda (or a function literal) that takes a parameter, called x, append it to a string
"Dude: "
and returns it. This definition is assigned to the valuef
. Since the valuef
was declared withInt => String
,x
will take on the typeInt
when the compiler infers its type. In Scala the last expression of a function body is the return statement, which also happens to be aString
in this case, which fits our declaration. In addition, in Java and Scala, the operator+
is overloaded. When you try to add aString
to anInt
, the result would be a string concatenation of the string value and the integer.Now check this out:
This time around,
f
wasn't declared with a type, it's type is inferred from it's definition(x:Int) => "Dude: " + x
, which is a function literal that takes a parameter namedx
of typeInt
and returns aString
. It should be clear that the 2 versions are equivalent now.Now as an exercise, try to write a few more versions that use the keyword
def
. When you are done, type all thosef()
s out in the REPL and observe their signatures. It should be clear as day by then.是一样的。您的两个版本派生的完整版本是这样的:
语言规范第 6.23 节说,如果参数的预期类型是已知的,那么您可以省略您的参数中的参数类型。匿名函数,结果如下:
然后,引用规范:“在单个无类型形式参数的情况下, (x ) => e 可以缩写为 x => e。”这将导致:
...这是您的第一个版本。
但是,如果您在匿名函数中指定了参数的类型,大多数情况下 Scala 将能够推断出匿名函数的类型,因此无需指定参数的类型。明确地发挥作用。这并不意味着这样做是错误的。这只是多余的。因此,如果您删除保存匿名函数的变量的类型定义,您将获得第二个定义。
您会期望 - 鉴于此 - 也应该可以像这样定义您的函数:
但是,这会让编译器感到困惑。 (规范对此做了一些说明。我只是还没有找到它。)如果您确实想要指定匿名函数的参数类型(正如我所说,没有理由来做到这一点),并且您想省略括号,那么这将起作用:
It's the same. The full version from which both of your versions are derived is this:
Section 6.23 of the language specification says that if the expected type of the parameters is known, then you can omit the type of the parameters in your anonymous function, which results in this:
Then, quoting the specification: "In the case of a single untyped formal parameter, (x ) => e can be abbreviated to x => e." Which will result in this:
... which is your first version.
However, if you do specify the types of the parameters in your anonymous function, in most cases Scala will be able to infer the type of your anonymous function, so there is no need to specify the type of the function explicitly. That doesn't mean it's wrong to do so. It's just redundant. So if you would drop the type definition of the variable holding your anonymous function, you get your second definition.
You would expect that - given this - it should also be possible to define your function like this:
However, this will confuse the compiler. (The specification says something about it. I just haven't been able to find it yet.) If you do want to specify the parameter type of your anonymous function (as I said, there is not reason to do it), and you feel like omitting the parentheses, then this will work: