我决定将下面的C#中的课程移植到F#作为练习。
很难。我只注意到三个问题
1)问候是可见的 2)我不能让v成为静态类变量 3)我不知道如何在构造函数中设置greet成员。
我如何解决这些问题?代码应该足够相似,我不需要更改任何C#源代码。 ATM仅限Test1.v = 21;不起作用
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CsFsTest
{
class Program
{
static void Main(string[] args)
{
Test1.hi("stu");
new Test1().hi();
Test1.v = 21;
var a = new Test1("Stan");
a.hi();
a.a = 9;
Console.WriteLine("v = {0} {1} {2}", a.a, a.b, a.NotSTATIC());
}
}
class Test1
{
public int a;
public int b { get { return a * 2; } }
string greet = "User";
public static int v;
public Test1() {}
public Test1(string name) { greet = name; }
public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
public int NotSTATIC() { return v; }
}
}
F#
namespace CsFsTest
type Test1 =
(*
public int a;
public int b { get { return a * 2; } }
string greet = "User";
public static int v;
*)
[<DefaultValue>]
val mutable a : int
member x.b = x.a * 2
member x.greet = "User" (*!! Needs to be private *)
[<DefaultValue>]
val mutable v : int (*!! Needs to be static *)
(*
public Test1() {}
public Test1(string name) { greet = name; }
*)
new () = {}
new (name) = { }
(*
public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
public int NotSTATIC() { return v; }
*)
static member hi(greet) =
printfn "hi %s" greet
member x.hi() =
printfn "hi %s #%i" x.greet x.v
member x.NotSTATIC() =
x.v
答案 0 :(得分:10)
F#语言有一些在C#中没有任何等价物的构造,但它几乎可以在C#中使用。这意味着如果您只是将代码从C#转换为F#,那么您最终只会使用F#的一个子集。因此,有时候寻找一些特定的F#构造会更好。
我认为这也是静态成员的情况。除了类之外,您还可以使用模块组织F#代码,模块提供了一种自然的方式来声明静态数据和函数。以下是问候模块的示例:
// modules are automatically 'static' (from the C# point of viedw)
module Greetings =
// public mutable field inside a module
let mutable how = "Hello "
// global function that uses the field
let greet name =
Console.WriteLine(how + name)
// modify the global field and invoke global function
Greetings.how <- "Ahoj "
Greetings.greet("Tomas")
如果您需要一些静态功能和一些实例功能,通常很容易在模块和标准类之间拆分功能。显而易见的好处是它为您提供了更简单的语法,但它也可以帮助构建代码:
type Person(name) =
member GreetMe() =
Greetings.greet(name)
如果要将模块中的成员隐藏起来,可以将其声明为private
或internal
。例如,如果您只想使how
字段对程序集可访问,则可以写:
let mutable internal how = "Hello "
我认为这会为您提供更多惯用的F#代码,因此在编写F#代码时我可能更喜欢这种编程风格。如果您打算在C#中使用它,那么模块将显示为静态类,它们也很容易使用。
作为旁注,通常建议避免使用太多可变成员。但是,如果您将它们用于某种配置,那么我认为它没问题。
答案 1 :(得分:5)
下面是一些针对C#客户端编译的F#。
在.NET中,很少公开公共领域;我会建议反对它。用于公开字段的F#语法有点麻烦。
namespace CsFsTest
open System
type Test1 =
val mutable private greet : string
[<DefaultValue>]
val mutable public a : int
[<DefaultValue>]
static val mutable private vv : int
static member v with get() = Test1.vv
and set(x) = Test1.vv <- x
member this.b = this.a*2
static member hi(greet:string) = Console.WriteLine("Hi {0}", greet)
member this.hi() = Console.WriteLine("Hi {0} #{1}", this.greet, Test1.v)
new() = { greet = "User" }
new(name : string) = { greet = name }
member this.NotSTATIC() = Test1.v
答案 2 :(得分:2)
您将greet定义为属性。它不需要是一个。
// these are the same
member x.greet = "User"
member x.greet with get() = "User"
它可以只是一个变量。
val mutable private greet : string
new () = { greet = "User" }
new (name) = { greet = name }
F#不允许您拥有公共静态类变量。你必须使用一个getter / setter。