简体   繁体   English

试图理解F#类定义语法

[英]Trying to understand F# class definition syntax

I'm approaching now to F# classes after learning a lot about the most important features of this language. 在了解了这门语言最重要的功能后,我现在正在接近F#课程。 Well, the class definition syntax is not simple to understand, but some of the main concepts are now clear to me, but others do not. 那么,类定义语法并不容易理解,但是现在我清楚了一些主要概念,但其他概念却没有。

1) The first thing I would like to know is just a CORRECT/NOT CORRECT. 1)我想知道的第一件事就是正确/不正确。 I understood that classes can be defined in two ways: 我知道可以用两种方式定义类:

  • Implicit classes. 隐含的类。 These classes have one constructor only, and in the first lines of the class, it is necessary to define, using the let binding, all internal variables assigning them a value. 这些类只有一个构造函数,在类的第一行中,有必要使用let绑定定义所有内部变量,为它们赋值。
  • Explicit classes. 显式类。 These classes have many constructors. 这些类有许多构造函数。 They accept, through the val binding, non-initialized values. 它们通过val绑定接受未初始化的值。 These values MUST ALL BE INITIALIZED in constructors. 这些值必须在构造函数中初始化。 If a constructor fails defining a value for at least one of the private variables defined using the val binding, the compiler will get mad. 如果构造函数无法为使用val绑定定义的至少一个私有变量定义值,编译器就会生气。

IS IT CORRECT??? 这是对的吗???

2) I have a problem understanding the syntax for the constructor in explicit classes. 2)我在理解显式类中构造函数的语法时遇到问题。 Consider the following: 考虑以下:

Here's the first version: 这是第一个版本:

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a;
      myother = b;
   }

Here's the second version: 这是第二个版本:

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a (* No semicolon *)
      myother = b (* No semicolon *)
   }

Here's the last version: 这是最后一个版本:

(* DOES NOT COMPILE :( *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = 
      myval = a (* Using the normal indent syntax, without {} *)
      myother = b (* Using the normal indent syntax, without {} *)

I do not understand why the first two versions compile and the third, that uses the regular indentation syntax, does not. 我不明白为什么前两个版本编译而第三个使用常规缩进语法却没有。 This problem occurs only in constructors because on members I can use the indent syntax 此问题仅在构造函数中发生,因为在成员上我可以使用缩进语法

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a (* No semicolon *)
      myother = b (* No semicolon *)
   }
   (* Indentation accepted, no {} to be inserted *)
   member self.mymember =
      let myvar = myval
      myvar + 10

Why the new function (the constructor) needs {} brackets????? 为什么新函数(构造函数)需要{}括号????? I do not like it, because it seems that a sequence is considered. 我不喜欢它,因为它似乎考虑了序列。 Furthermore, my code compiles also when, in the {} rackets, between one instruction and the other, no semicolon is inserted. 此外,我的代码也在{}球拍中,在一条指令和另一条指令之间,没有插入分号时进行编译。 WHY???? 为什么????

You wrote (emphasis mine): 你写的(强调我的):

Implicit classes. 隐含的类。 These classes have one constructor only , and in the first lines of the class, it is necessary to define, using the let binding, all internal variables assigning them a value. 这些类只有一个构造函数 ,在类的第一行中,有必要使用let绑定定义所有内部变量,为它们赋值。

That's not actually true - you can use the implicit syntax to define class with multiple constructors. 这实际上并不正确 - 您可以使用隐式语法来定义具有多个构造函数的类。 In fact, I think it is a good idea to use the implicit class syntax almost always (because it makes declarations simpler). 实际上,我认为几乎总是使用隐式类语法是个好主意(因为它使声明更简单)。 Implicit classes have one primary constructor which is the one you get implicitly - this constructor should take the largest number of parameters (but it can be private): 隐式类有一个主要的构造函数 ,它是你隐式得到的 - 这个构造函数应该采用最大数量的参数(但它可以是私有的):

type Foo(a:int, b:int) =
  do printfn "hello"         // additional constructor code
  member x.Multiple = a * b  // some members
  new(x:int) = Foo(x, x)     // additional constructor

To make the constructor private, you can write 要使构造函数成为私有的,您可以编写

type Foo private (a:int, b:int) =
  ...

Then you can use the primary constructor just as a nice way to initialize all the fields. 然后,您可以使用主构造函数作为初始化所有字段的好方法。

Regarding 2), the body of a constructor is not like the body of a typical function - it has a restricted syntactic form, and within the { } section it can only contain a call to the parent constructor and assignments of fields (similar to record construction). 关于2),构造函数的主体不像典型函数的主体 - 它具有受限的句法形式,并且在{ }部分内它只能包含对父构造函数的调用和字段的赋值(类似于记录)施工)。 When defining a normal member you can't wrap the individual expressions in { } even if you wanted to (that is, the braces are not optional in this context, they are forbidden). 在定义普通成员时,即使您想要(即,在此上下文中大括号不是可选的,也禁止它们),您也无法将各个表达式包装在{ }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM