F# 代码块
最后修改日期:2025 年 5 月 17 日
F# 使用基于缩进的代码块来组织代码结构。与使用大括号的语言不同,F# 通过一致的缩进确定代码块的范围。这创造了干净、可读的代码,并具有视觉结构。
基本代码块
F# 中的代码块是通过在函数、循环和条件等结构下进行缩进来创建的。标准约定是每个级别缩进 4 个空格。
// Function with a code block
let calculateTotal (price: float) (quantity: int) =
let subtotal = price * float quantity
let tax = subtotal * 0.08
subtotal + tax // Last expression is return value
printfn "Total: %.2f" (calculateTotal 25.99 3)
// Conditional with blocks
let checkNumber n =
if n > 0 then
printfn "Positive number"
printfn "Double: %d" (n * 2)
else
printfn "Non-positive number"
printfn "Absolute: %d" (abs n)
checkNumber 5
checkNumber -3
这展示了函数和条件中的基本代码块。代码块中的所有语句必须对齐到相同的缩进级别。当缩进返回到前一个级别时,代码块结束。
λ dotnet fsi basic_blocks.fsx Total: 84.21 Positive number Double: 10 Non-positive number Absolute: 3
嵌套代码块
可以通过增加额外的缩进级别来嵌套代码块。每个嵌套的代码块都会增加缩进,从而创建清晰的视觉层次结构。
let analyzeNumbers numbers =
if List.isEmpty numbers then
printfn "No numbers to analyze"
else
printfn "Number count: %d" (List.length numbers)
let evens, odds =
numbers
|> List.partition (fun x -> x % 2 = 0)
printfn "Even numbers: %A" evens
printfn "Odd numbers: %A" odds
if not (List.isEmpty evens) then
printfn "Even stats:"
printfn " Min: %d" (List.min evens)
printfn " Max: %d" (List.max evens)
if not (List.isEmpty odds) then
printfn "Odd stats:"
printfn " Min: %d" (List.min odds)
printfn " Max: %d" (List.max odds)
analyzeNumbers [1..10]
此示例显示了多级嵌套代码块。外部函数代码块包含条件代码块,而条件代码块本身又包含其他代码块。每个级别都比其父级缩进更多。
λ dotnet fsi nested_blocks.fsx Number count: 10 Even numbers: [2; 4; 6; 8; 10] Odd numbers: [1; 3; 5; 7; 9] Even stats: Min: 2 Max: 10 Odd stats: Min: 1 Max: 9
代码块中的 Let 绑定
Let 绑定可以在代码块内创建局部作用域。这些绑定仅在其包含的代码块内可见,有助于组织复杂的逻辑。
type User = { Name: string; Age: int }
let processUser user =
let isValid =
not (System.String.IsNullOrWhiteSpace user.Name) &&
user.Age > 0
if isValid then
let greeting =
if user.Age >= 18 then "Hello, " + user.Name
else "Hi, " + user.Name + " (minor)"
printfn "%s" greeting
let accountType =
match user.Age with
| a when a >= 65 -> "Senior"
| a when a >= 18 -> "Adult"
| _ -> "Junior"
printfn "Account type: %s" accountType
else
printfn "Invalid user data"
processUser { Name = "Alice"; Age = 30 }
processUser { Name = ""; Age = 15 }
这演示了代码块内的局部 Let 绑定。每个绑定仅在其作用域内可用。greeting 和 accountType 绑定只能在 isValid 为 true 的代码块中访问。
λ dotnet fsi let_blocks.fsx Hello, Alice Account type: Adult Invalid user data
表达式代码块
F# 允许创建临时表达式代码块来组织代码或限制作用域。这些代码块会评估其最后一个表达式,并且可以出现在任何地方。
let calculateComplexValue x y =
let intermediate =
let a = x * x
let b = y * y
a + b // This value becomes 'intermediate'
let result =
if intermediate > 100 then
let scaled = intermediate / 10
scaled + 5
else
intermediate * 2
result
printfn "Result: %d" (calculateComplexValue 5 8)
// Standalone expression block
let randomValue =
let r = System.Random()
let a = r.Next(10)
let b = r.Next(10)
a + b
printfn "Random sum: %d" randomValue
这些示例显示了在函数内部和作为独立值使用的表达式代码块。每个代码块创建自己的作用域并评估其最后一个表达式。
λ dotnet fsi expression_blocks.fsx Result: 13 Random sum: 11
Module 和 Namespace 代码块
更大的代码组织使用 Module 和 Namespace 代码块。这些为相关功能创建命名作用域,并遵循相同的缩进规则。
namespace MathOperations
module Arithmetic =
let add x y = x + y
let subtract x y = x - y
module Advanced =
let multiply x y = x * y
let divide x y = x / y
module Geometry =
let circleArea radius =
System.Math.PI * radius * radius
let rectangleArea width height =
width * height
// Usage from another file would be:
// open MathOperations.Arithmetic
// printfn "%d" (add 5 3)
这展示了 Namespace 和 Module 代码块。Arithmetic Module 包含一个内部的 Advanced Module。所有内容都根据其各自的 Module 声明进行缩进。
特殊代码块形式
F# 有几种特殊的代码块形式用于特定目的,例如计算表达式和类定义,它们遵循类似的缩进规则。
// Computation expression block
let safeDivide x y =
match y with
| 0 -> None
| _ -> Some (x / y)
printfn "Safe divide: %A" (safeDivide 10 2)
printfn "Safe divide: %A" (safeDivide 10 0)
// Class definition block
type Person(name: string, age: int) =
member _.Name = name
member _.Age = age
member _.Greet() =
printfn "Hello, my name is %s" name
member _.IsAdult =
age >= 18
let p = Person("Alice", 30)
p.Greet()
这些示例演示了特殊的代码块形式。option 计算表达式和 Person 类都使用缩进的代码块来定义其内容,遵循 F# 的标准缩进规则。
λ dotnet fsi special_blocks.fsx Safe divide: Some 5 Hello, my name is Alice
最佳实践
一致的缩进在 F# 中至关重要。遵循这些实践来获得干净、可维护的代码块。
// Good practices example
module CleanCode =
// Use consistent 4-space indents
let calculate x y =
let intermediate =
let a = x * 2
let b = y * 3
a + b
if intermediate > 100 then
printfn "Large result"
intermediate / 10
else
printfn "Normal result"
intermediate
// Keep blocks focused
let processData data =
let cleanData =
data
|> List.filter (fun x -> x > 0)
|> List.map (fun x -> x * 2)
let sum = List.sum cleanData
let avg = float sum / float (List.length cleanData)
(sum, avg)
// Avoid mixing tabs and spaces
// Avoid inconsistent indentation
// Keep block sizes reasonable
此示例演示了良好的实践:一致的 4 个空格缩进、集中的代码块和干净的组织。该 Module 展示了结构良好的 F# 代码。
F# 代码块通过缩进提供了一种干净、视觉上清晰的代码组织方式。通过理解代码块结构并遵循一致的实践,您可以编写既优雅又可维护的 F# 代码。基于缩进的方法减少了混乱,同时使作用域和结构立即可见。