Паттерны переменных и типов

Последнее обновление: 14.12.2023

Паттерны переменных

Паттерны переменных (variable pattern) позволяют присвоить сопоставляемое значение переменной, которую затем можно использовать в выражении справа от оператор ->. Сам по себе шаблон переменной соответствует любому вводу, но шаблоны переменных часто применяются внутри других шаблонов, что позволяет разложить на переменные более сложные структуры, такие как кортежи и массивы.

Например, если варианты объединений определяют некоторые поля, то мы можем получить эти поля в переменные:

type Contact = 
    | Email of emailAddress:string
    | Phone of phoneNumber:string
    | Post of city:string * street:string * building:string


let printContact contact = 
    match contact with 
    | Email emailAddr -> printfn $"Email: {emailAddr}"
    | Phone phoneNumber -> printfn $"Тел.: {phoneNumber}"
    | Post (city = c; street = s; building = b) -> printfn $"Адрес офиса: город {c}, {s}, {b}"

let contact1 = Email("some@xyzmail.com")
let contact2 = Phone("+79876543210")
let contact3 = Post("Минас-Тирит", "ул. Вязов", "д.13")

printContact contact1
printContact contact2
printContact contact3

Здесь объединение Contact определяет ряд вариантов, которые имеют поля. В конструкции match получаем эти поля в переменные. Если вариант объединения имеет только одно поле, то для его можно указать переменную справа от названия варианта:

Email emailAddr -> printfn $"Email: {emailAddr}"

В данном случае поле emailAddress варианта Email попадает в переменную emailAddr.

Если полей несколько, то можно их получить как части кортежа:

Post (city = c; street = s; building = b) -> printfn $"Адрес офиса: город {c}, {s}, {b}"

Здесь поле city попадает в переменную с, поле street - в переменную s, поле building - в переменную b.

Консольный вывод программы:

Email: some@xyzmail.com
Тел.: +79876543210
Адрес офиса: город Минас-Тирит, ул. Вязов, д.13

Паттерн типов

Паттерн типов (type pattern) применяется для проверки типа выражения и обычно используется для проверки принадлежности производным типам:

type A() = class end
type B() = inherit A()
type C() = inherit A()

let checkA (a: A) =
    match a with
    | :? B -> printfn "a is B"
    | :? C -> printfn "a is C"
    | _ -> ()

let obj1: A = B()
let obj2: A = C()

checkA obj1     // a is B
checkA obj2     // a is C

Здесь определан примитивнейшая иерархия классов, где есть базовый тип - A и есть производные типы B и C. Для проверки типа перед шаблоном типа указываем оператор :?:

:? B -> printfn "a is B"

Более практический пример:

type Person(name: string) = 
    member this.Name = name

type Employee(name: string, company: string) = 
    inherit Person(name)
    member this.Company = company

type Student(name: string, university: string) = 
    inherit Person(name)
    member this.University = university

let printPerson (p: Person) =
    match p with
    | :? Employee as emp -> printfn "%s работает в %s" emp.Name emp.Company
    | :? Student as st -> printfn "%s учится в %s" st.Name st.University
    | _ -> printfn "%s не работает и не учится" p.Name

let obj1 = Person("Tom")
let obj2 = Employee("Bob", "LocalComp")
let obj3 = Student("Sam", "СуперУнивер")

printPerson obj1    // Tom не работает и не учится
printPerson obj2    // Bob работает в LocalComp
printPerson obj3    // Sam учится в СуперУнивер

Здесь есть базовый класс Person. От него наследуются классы Employee (класс работника) и Student (класс учащегося). Эти классы добавляют к унаследованному функционалу разные свойства. И, допустим, в функции printPerson мы хотим вывести на консоль информацию об объекте Person. Но поскольку этот объект в реальности может представлять и типы Employee и Student, то применяем паттерн типов

| :? Employee as emp -> printfn "%s работает в %s" emp.Name emp.Company

Кроме того, здесь применяется выражение as, которое привязывает сопоставленное значение к идентификатору (в данном случае emp). Далее мы можем использовать идентификатор emp справа от оператора ->, и этот идентификатор будет рассматриваться как значение типа Employee.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850