【问题标题】:Controlling access on fields in F# types控制对 F# 类型中的字段的访问
【发布时间】:2019-10-17 09:46:10
【问题描述】:

我正在使用 F# 为其中一个应用程序编写域逻辑。我想控制对 F# 中的类型定义的字段的访问,以便我可以实现构建器模式和控制类型实例化。

想要在 C#/Java 的构建器模式中做类似的事情。

请推荐。

例如 让人 = { 名称:字符串 年龄:数字 工资:字符串 }

所以我想确保 person 应该总是用 Name 和 Age 实例化。但是薪水应该是可选的。实例化应该发生在构建器模式中。

【问题讨论】:

  • 如果您需要控制访问,您不能使用记录,而应该创建一个对象 (docs.microsoft.com/en-us/dotnet/fsharp/language-reference/…)。鉴于 Builder 模式是一种面向对象的方法,无论如何,对象会更适合。
  • 您想在 F# 中使用面向对象的方法,还是想使用更多的 F#-y 函数方法?

标签: f# f#-interactive c#-to-f# f#-3.0


【解决方案1】:

您不能将单个记录字段设为privateinternal,但您可以将所有字段设为privateinternal。这隐藏了所有字段,因此您必须公开那些您希望作为成员访问的字段。您还可以添加静态方法来创建新值。例如:

type Person = 
  private { 
    name : string
    age : int 
    salary : int option }
  member x.Name = x.name
  member x.Age = x.age
  member x.Salary = x.salary

  static member Create(name:string, age:int) = 
    { name = name; age = age; salary = None }
  member x.WithSalary(s) =
    { x with salary = Some s }

现在您无法直接访问字段或创建记录,但您可以使用CreateWithSalary

Person.Create("Joe", 60).WithSalary(10000)

【讨论】:

    【解决方案2】:

    您可以使用普通函数来实现构建器模式。我认为没有理由在这里使用对象:

    type person =
      private {
        name: string
        age: int
        salary: int option
      }
    
    let name person = person.name
    let age person = person.age
    let salary person = person.salary
    
    let create name age = 
      { name = name; age = age; salary = None }
    
    let withSalary salary person =
       { person with salary = Some salary }
    
    create "Joe" 60
      |> withSalary 10000
      |> name
    

    【讨论】:

      【解决方案3】:

      正如评论中所指出的,您似乎正在尝试使用没有对象的面向对象模式,这几乎不是一个好主意。

      如果你决定使用 F# 类型,你会这样做:

      type Employee = {
          name: string
          age: int
          salary: int option
      }
      
      let person1 = {
          name = "Mike",
          age = 42,
          salary = Some 4200
      }
      let person2 = {
          name = "Sue",
          age = 37,
          salary = None
      }
      

      省略姓名或年龄会导致编译时错误,就像使用 person1 或 person2 而不检查薪水是否存在一样。

      要使用私有数据实现类似于构建器模式的东西,请执行以下操作:

      type Employee = private {
          name: string
          age: int
          salary: int option
      }
      
      let name employee = employee.name
      let employee name age = { name = name; age = age; salary = None }
      let withSalary salary employee = { employee with salary = Some salary }
      
      let mike = employee "Mike" 42 |> withSalary 4200
      
      mike.name  //return name of this employee
      

      【讨论】:

        猜你喜欢
        • 2012-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-11
        • 1970-01-01
        • 2020-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多