📅  最后修改于: 2021-01-01 14:54:34             🧑  作者: Mango
下面列出了最常见的F#面试问题和答案。
F#是一种计算机编程语言。它是由Microsoft设计和开发的。它支持功能,面向对象和命令式编程方法。您可以使用此编程语言创建应用程序。
F#具有许多功能。以下是F#的主要功能:
F#提供了一组丰富的数据类型。它有助于处理任何数据,无论是科学数据,业务分析数据还是其他数据。您都可以在此处查看数据类型表。
F#中的数据类型
Types | Data Types |
---|---|
Primitive data types | char, byte, bool, int, float |
Derived data types | class, array, list, records, sequence |
Enumeration | enum |
Unit type | It is used if other data types are not specified. |
单位类型是指示没有特定值的类型。单位类型只有一个值。如果没有其他值,则此值充当占位符。
例:
let function1 x y = x + y
function1 10 20 // this line results a compiler warning
// changing the code to the following and eliminates the warning
let result = function1 10 20
// Use this if you are calling the function and don't want the return value
function1 10 20 |> ignore
转换是将一种类型转换为另一种类型的过程。 F#主要提供两个运算符来处理上播和下播。 :>运算符用于向上转换对象,而:?>运算符用于向下转换对象。
例:
type BaseClass() =
class
member this.ShowClassName()=
printfn "BaseClass"
end
type DerivedClass() =
class
inherit BaseClass()
member this.ShowClassName()=
printfn "DerivedClass"
end
let baseClass = new BaseClass()
let derivedClass : DerivedClass = new DerivedClass()
baseClass.ShowClassName()
derivedClass.ShowClassName()
let castIntoBaseClass = derivedClass :> BaseClass // upcasting
castIntoBaseClass.ShowClassName()
let castIntoDerivedClass = baseClass :?> DerivedClass // downcasting
castIntoDerivedClass.ShowClassName()
运算符只是用于执行操作的符号。可以有多种类型的运算,例如算术运算,按位运算,逻辑运算等。
可以使用以下类型的运算符来执行F#语言的不同类型的运算。
在F#中,功能可以由其他功能组成。这是一个组合过程,其中一个函数代表两个组合函数的应用。 F#函数流水线允许我们在链中调用函数。流水线运算符将一个函数和一个参数作为操作数,并返回一个值。
let function1 name=
name + " FSharp"
let function2 name =
name + " Programming"
let programmingName = function1 >> function2
let result = programmingName "Hello"
printf "%s" result
let function1 name=
name + " FSharp"
let function2 name =
name + " Programming"
let result = "Hello" |> function1 |> function2
printf "%s" result
Lambda表达式是未命名或匿名函数。有时,可以定义一个lambda表达式来代替定义全名函数。它优化了代码。您必须使用fun关键字定义lambda表达式。
let result = (fun a -> a+1) 100
printf "%d" result
F#内联函数是直接集成到调用代码中的函数。它有助于优化代码,有时还可以提高性能。
type InlineClass() =
class
member inline this.inlineFunction(a) = a*a
end
let obj = new InlineClass()
let result = obj.inlineFunction 2
printf "%d" result
绑定是将标识符或函数与值相关联的过程。 Let关键字用于将标识符绑定到值。在F#中,我们使用let关键字声明变量,函数和私有类成员。
我们使用let关键字在F#中定义一个函数。
let ShowName() =
printf "Hello FSharp"
ShowName()
Do绑定用于执行代码而无需定义函数或任何类型。您可以通过在F#中使用do绑定来编写独立的代码。
type DoBindingClass() =
class
do printf "Hello FSharp"
end
new DoBindingClass()
F#允许类型的注释,这样就可以明确提到标识符或参数或函数的返回类型的类型。您必须使用:(冒号)在F#中应用注释。
let a:int = 10
printf "%d" a
类型推断意味着在编写代码时,您无需指定值或变量的类型。 F#编译器的功能足以推断出值的类型。
let add a b = //Here, all parameters are inferred to int because of passing values during calling
a+b // Return type of this function is int because the type of this expression is int.
printf "%d" (add 10 20)
如果代码未明确指定任何类型,则编译器将考虑泛型。这称为自动概括。它有助于编写通用代码而不会增加复杂性。
在F#中,元组是匿名值的集合。值可以相同或不同。它也使我们也可以将表达式作为值。
let (id,name) = (1, "Fsharp")
printfn "%d" id
printfn "%s" name
是的,通过使用元组,您可以在函数返回多个值。
let TupleExample a b =
let c = a+b
let d = a-b
(c, d)
let tupleValues = TupleExample 50 10
printf "%A" tupleValues
它是相同类型元素的不可变集合。它保持元素的顺序。
let list = [1;2;3;4;5;6;7;8;9]
for i in list do
printfn "%d" i
数组是相同类型数据的可变集合。它从索引0开始到n-1,其中n是数组的长度。
let arr = [| 1; 2; 3; 4; 5; |] // Creating and initializing array
for i = 0 to arr.Length-1 do // Traversing of array
printfn "%d" arr.[i]
序列是一系列相同类型的元素。它提供了比列表更好的性能。
您可以创建如下的序列表达式。在这里,我们使用了Seq.iter()函数来迭代序列。我们还可以使用循环或数组格式说明符来迭代序列元素。
let seq1 =
seq { 0 .. 10 }
Seq.iter(fun a->printf " %d" a)seq1
当函数或变量不存在任何值时,将使用选项类型。它提供表达式Some和值None用于处理空值或变量。
let sub a b =
if(a>b) then
Some(a-b)
else None
printf "%A" (sub 20 10)
F#允许您编写通用函数,方法,类型,变量等。它有助于避免每种类型的代码重复。通过编写通用代码,您可以将其应用于任何类型或值。
let genericFunctionExample<'T> x y =
printfn "%A %A" x y
genericFunctionExample 1 2
记录用于存储标签和值形式的元素。它可以存储任何数据。您不必将相同的类型值存储为列表。记录默认是不可变的,因此您不能修改原始记录。
type RecordExample = { x : float; y: float; z: float; }
let getRecordValues = { x = 2.0; y = 1.0; z = 0.0; }
printf "%A\n" getRecordValues // Access all values of record
printf "%f" getRecordValues.x // Access individual values of record
枚举通常被称为枚举。它是标签和值对的组合。标签被分配给值的子集。您可以使用它们代替字面量,以使代码更具可读性和可维护性。
type Year =
| January = 0
| Fabruary = 1
| March = 2
| April = 3
// Use of an enumeration.
let monthName = enum(3)
printf "%A" monthName
let monthLiteral : Year = Year.January
let n = int monthLiteral
printf "\n%d" n
参考单元引用存储位置。它允许您创建可变值。 F#默认使用不可变数据结构。
let refVariable = ref 50
printf "%d" refVariable.Value
F#结构是用于组织数据的数据结构,它是值类型,比类有效。它不允许let绑定,因此必须使用val关键字声明字段。
type Book = struct
val title : string
val author: string
val price : float
new (title, author, price) = // Constructor
{title = title; author = author; price = price;}
end
let book = new Book("FSharp Programming", "Chris Smith", 100.0) // Calling Constructor
printfn "Title : %s " book.title
printfn "Author : %s" book.author
printfn "Price : $%0.2f" book.price
这是一个有用的数据结构。它有助于存储异构数据。联合用于表示树数据结构。它提供了案例,每个案例都包含异构数据。
type Calcualte =
| Add of val1 : int * val2 : int
| Multiply of val1 : int * val2 : int
let compute vall =
match vall with
| Add (val1, val2) -> val1+val2
| Multiply (val1, val2)->val1*val2
let addition = compute (Add(10,10))
let multiplication = compute (Multiply(2,5))
printf "Addition = %d\nMultiplication = %d" addition multiplication
该对象是真实世界的实体。它可以是任何东西-手机,汽车,足球等。
对象是类的实例,我们可以使用此类的对象来访问该类的所有成员。
让我们看一下如何在F#中创建对象的示例。
let objectName = new ClassName()
类是对象的模板或蓝图。它用于封装数据成员和成员方法。它可以包含字段,方法,构造函数,静态方法等。
type Student (id,name)=
class
member x.show =
printf "%d \n%s" id name
end
let a = new Student (12,"FSharp")
a.show
在F#中,构造函数与其他.Net语言有所不同。总是有可能带有或不带有参数的主要构造函数。这些参数的范围遍及整个类。
type Employee(name) =
class
do printf "%s" name
end
let e = new Employee("FSharp")
在F#中,一个self用于引用当前类类型的对象。 Self与C#和Java中的此关键字相同。您可以根据需要命名自己的标识符。您不限于.Net语言这样的名称或self。
type Employee(id,name) as this =
let id = id
let name = name
do this.Display() // This is how we can use self(this) object
member this.Display() =
printf "%d %s" id name
let e =new Employee(100, "Rajkumar")
在F#中,static是关键字。它用于制作静态字段或静态方法。静态不是对象的一部分。它具有其存储空间来存储静态数据。它用于在对象之间共享通用属性。
type Account(accno,name) = class
static let rateOfInterest = 8.8
member this.display()=
printfn "%d %s %0.2f" accno name rateOfInterest
end
let a1 = new Account(101,"Rajkumar")
let a2 = new Account(102, "john")
a1.display()
a2.display()
在F#中,继承是子类自动获取其父类的所有属性和行为的过程。它用于重用代码。
type Employee(name:string) =
class
member this.ShowName() = printf"Name = %s\n" name
end
type Manager(name,salary:int) =
class
inherit Employee(name)
member this.ShowSalary() = printf"Salary = $%d" salary
end
let manager = new Manager("Rajkumar",10000)
manager.ShowName()
manager.ShowSalary()
方法覆盖是面向对象编程方法的功能。它有助于实现多态性。我们可以使用继承来实现方法重写。
type Employee() =
class
abstract ShowName : unit -> unit
default this.ShowName() = printfn"This is base class method"
end
type Manager() =
class
inherit Employee()
override this.ShowName() = printf "This is derived class method"
end
let employee = new Employee()
let manager = new Manager()
employee.ShowName()
manager.ShowName()
抽象类用于提供类成员的完整实现。它可能包含非抽象方法。继承抽象类的类必须提供该抽象类的所有抽象方法的实现。
[]
type AbstractClass() =
class
abstract member ShowClassName : unit -> unit
end
type DerivedClass() =
class
inherit AbstractClass()
override this.ShowClassName() = printf "This is derived class."
end
let a = new DerivedClass()
a.ShowClassName()
F#提供接口类型。它提供了纯抽象。它是抽象方法的集合。
type IEmployee =
abstract member ShowName : unit -> unit
type Manager(id:int, name:string) =
interface IEmployee with
member this.ShowName() = printfn "Id = %d \nName = %s" id name
let manager = new Manager(100,"RajKumar")
//manager.ShowName() // error: you can't directly access interface abstract method by using class object.
// so, we need to upcast class type object to interface type by using :> operator.
(manager :> IEmployee).ShowName()
类型扩展允许您将新成员添加到先前定义的对象类型。
type ClassExtension() =
member this.ShowBefore() = printfn"Class before extension"
// Define type extension.
type ClassExtension with
member this.ShowAfter() = printfn"Class after extension"
let classExtension = new ClassExtension()
classExtension.ShowBefore()
classExtension.ShowAfter()
在F#中,委托是引用类型。它允许我们将函数作为对象调用。这是该语言的功能。与其他功能编程语言相比,它具有优势。
type Deligate() =
static member mul(a : int, b : int) = a * b
member x.Mul(a : int, b : int) = a * b
type Multiply = delegate of (int * int) -> int
let getIt (d : Multiply) (a : int) (b: int) =
d.Invoke(a, b)
let d : Multiply = new Multiply( Deligate.mul )
for (a, b) in [(5, 8) ] do
printfn "%d * %d = %d" a b (getIt d a b)
F#对象表达式是一个特殊的表达式。它基于现有的基本类型,接口或接口集创建一个匿名对象类型的新实例。
let ex =
{
new System.Exception() with member x.ToString() = "Hello FSharp"
}
printfn "%A" ex
异常处理是处理程序异常终止的标准机制。异常是程序执行期间发生的情况。它可能导致异常终止程序,例如被零除或空指针。
let ExExample a b =
let mutable c = 0
c <- (a/b)
printfn "Rest of the code"
ExExample 10 0
在F#中,可以创建用户定义的异常。它提供了根据需求定义自定义异常的灵活性。
let ExExample a b =
let mutable c = 0
try
c <- (a/b)
with
| :? System.DivideByZeroException as e -> printfn "%s" e.Message
printfn "Rest of the code"
ExExample 10 0
在F#中,可以显式引发异常。您可以引发自定义异常。您也可以通过使用预定义的Exception方法(例如Failwith和InvalidArgs)来引发异常。
let TestAgeValidation age =
try
if (age<18) then failwith "Sorry, Age must be greater than 18"
with
| Failure(e) -> printfn "%s" e;
printf "Rest of the code"
TestAgeValidation 10
let TestInvalidArgument age =
if(age<18) then
invalidArg "TestInvalidArgument" ("Sorry, Age must be greater than 18")
TestInvalidArgument 10
断言表达式是F#的调试功能。您可以使用它来测试表达式。在调试模式下失败时,它将生成一个系统错误对话框。
let divide (x:int, y:int):int =
assert (x>0)
let z = (x/y)
z
let result = divide(10,2)
printf "%d" result
该模块是类,函数和类型的集合。它有助于组织相关代码,因此我们可以轻松维护代码。
open Arithmetic
printf "%d" (sub 20 10)
访问控制指定代码的可访问性。通过使用这些,您可以指定数据,方法,类等的范围。
F#中有3种访问控制。
F#在使用和使用关键字的帮助下管理资源。资源可以是数据,文件或网络等。它从操作系统或其他服务提供者那里获取资源,以便可以将其提供给其他应用程序。
open System.IO
let ReleaseFile fileName content =
using (System.IO.File.CreateText(fileName)) ( fun textFile ->
textFile.WriteLine("{0}", content.ToString() )
)
ReleaseFile "file/textFile.txt" "This is a text file. \nIt contains data."
在F#中,该属性用于为程序代码构造启用元数据。该属性可以应用于任何构造,例如函数,模块,方法和类型。
open System
[]
let updateSystem() =
printf "updating..."
updateSystem
在F#中,签名文件包含有关公共签名的信息。签名可以是一组程序元素,例如类型,名称空间和模块。
namespace FSharpPrograms
module Arithmetic =
val add : int * int -> int
val sub : int * int -> int
导入声明指定模块或名称空间。您可以引用其元素,而无需使用完全限定的名称。
open System
Console.WriteLine("Hello, this is F# here.")
“ base”关键字用作基类对象的名称。
它用于表示代码块的开始。
与分支相同。
Yield关键字可用于序列表达式中以产生序列值。
它用于指示递归函数。
它用于指示声明的程序元素是在某些其他程序集或二进制文件中定义的。
type name =
| case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ]
type2 ...]
| case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
这意味着,一旦将值分配给变量,就无法更改。
用于指示错误发生。
惰性计算是F#的功能。延迟计算不会立即进行评估。需要结果时执行。
let add x y = x+y
let result = lazy (add 10 10)
printfn "%d" (result.Force())
在F#中,您可以使用三斜杠(///)代码注释生成文档。 XML注释可以在代码文件(.fs)或签名(.fsi)文件中的声明之前。
let add x y = x+y
let result = lazy (add 10 10)
printfn "%d" (result.Force())