剖析 scala 中的简单函数声明

发布于 2024-10-21 23:33:51 字数 285 浏览 1 评论 0原文

这个例子来自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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╄→承喏 2024-10-28 23:33:51

他们是一样的。您可以通过两种不同的方式让 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 的类型是什么。这个值(在=的右侧)是一个函数,它接受一个I​​nt(因为你明确地说了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 declare f of type Int => 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 that x: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.

东风软 2024-10-28 23:33:51

好吧,我们开始吧:

line 1: val f: Int => String

读取为函数声明为带有签名的值,该签名将第一个输入值从 Int 类型映射到 String 类型的输出值

line 1: ... = x => "Dude: " + x

使用 lambda(或函数文字)读取为函数定义,该函数采用名为 x 的参数,将其附加到字符串“Dude:” 并返回它。该定义被分配给值f。由于值 f 是用 Int => 声明的。当编译器推断其类型时,Stringx 将采用 Int 类型。在 Scala 中,函数体的最后一个表达式是 return 语句,在本例中它也恰好是一个 String,这符合我们的声明。另外,在Java和Scala中,运算符+是重载的。当您尝试将 String 添加到 Int 时,结果将是字符串值和整数的字符串连接。

现在检查一下:

line: 2 val f = (x:Int) => "Dude: " + x

这一次,f 没有用类型声明,它的类型是从它的定义中推断出来的 (x:Int) =>; "Dude: " + x,这是一个函数文字,它采用 Int 类型的名为 x 的参数并返回 String 。应该清楚的是,这两个版本现在是等效的。

现在作为练习,尝试编写更多使用关键字 def 的版本。完成后,在 REPL 中键入所有这些 f() 并观察它们的签名。到那时应该就清楚了。

Ok here we go:

line 1: val f: Int => String

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 type String.

line 1: ... = x => "Dude: " + x

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 value f. Since the value f was declared with Int => String, x will take on the type Int when the compiler infers its type. In Scala the last expression of a function body is the return statement, which also happens to be a String in this case, which fits our declaration. In addition, in Java and Scala, the operator + is overloaded. When you try to add a String to an Int, the result would be a string concatenation of the string value and the integer.

Now check this out:

line: 2 val f = (x:Int) => "Dude: " + x

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 named x of type Int and returns a String. 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 those f()s out in the REPL and observe their signatures. It should be clear as day by then.

风吹过旳痕迹 2024-10-28 23:33:51

是一样的。您的两个版本派生的完整版本是这样的:

val f: Int => String = (x: Int) => "Dude:" + x

语言规范第 6.23 节说,如果参数的预期类型是已知的,那么您可以省略您的参数中的参数类型。匿名函数,结果如下:

val f: Int => String = (x) => "Dude:" + x

然后,引用规范:“在单个无类型形式参数的情况下, (x ) => e 可以缩写为 x => e。”这将导致:

val f: Int => String = x => "Dude:" + x

...这是您的第一个版本。

但是,如果您在匿名函数中指定了参数的类型,大多数情况下 Scala 将能够推断出匿名函数的类型,因此无需指定参数的类型。明确地发挥作用。这并不意味着这样做是错误的。这只是多余的。因此,如果您删除保存匿名函数的变量的类型定义,您将获得第二个定义。

val f = (x: Int) => "Dude:" + x

您会期望 - 鉴于此 - 也应该可以像这样定义您的函数:

    scala> val f: Int => String = x: Int => "Dude:" + x      
<console>:1: error: identifier expected but string literal found.
       val f: Int => String = x: Int => "Dude:" + x

                                    ^

但是,这会让编译器感到困惑。 (规范对此做了一些说明。我只是还没有找到它。)如果您确实想要指定匿名函数的参数类型(正如我所说,没有理由来做到这一点),并且您想省略括号,那么这将起作用:

val f: Int => String = { x: Int => "Dude:" + x }

It's the same. The full version from which both of your versions are derived is this:

val f: Int => String = (x: Int) => "Dude:" + x

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:

val f: Int => String = (x) => "Dude:" + x

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:

val f: Int => String = x => "Dude:" + x

... 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.

val f = (x: Int) => "Dude:" + x

You would expect that - given this - it should also be possible to define your function like this:

    scala> val f: Int => String = x: Int => "Dude:" + x      
<console>:1: error: identifier expected but string literal found.
       val f: Int => String = x: Int => "Dude:" + x

                                    ^

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:

val f: Int => String = { x: Int => "Dude:" + x }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文