구별된 공용 구조체
차별된 공용 구조체는 여러 개의 명명된 사례 중 하나일 수 있는 값(각각 다른 값 및 형식)을 지원합니다. 차별된 공용 구조체는 이질적인 데이터에 유용합니다. 유효한 사례 및 오류 사례를 포함하여 특수한 경우를 포함할 수 있는 데이터 한 인스턴스에서 다른 인스턴스로 형식에 따라 달라지는 데이터 작은 개체 계층 구조의 대안으로 사용할 수 있습니다. 또한 재귀 구분된 공용 구조체는 트리 데이터 구조를 나타내는 데 사용됩니다.
구문
[ attributes ]
type [accessibility-modifier] type-name =
| case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ] type2 ...]
| case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
[ member-list ]
설명
차별된 공용 구조체는 다른 언어의 공용 구조체 형식과 유사하지만 차이점이 있습니다. C++의 공용 구조체 형식 또는 Visual Basic의 변형 형식과 마찬가지로 값에 저장된 데이터는 고정되지 않습니다. 여러 가지 고유한 옵션 중 하나일 수 있습니다. 그러나 이러한 다른 언어의 공용 구조체와 달리 가능한 각 옵션에는 사례 식별자가 제공됩니다. 대/소문자 식별자는 이 형식의 개체가 될 수 있는 다양한 형식의 값에 대한 이름입니다. 값은 선택 사항입니다. 값이 없으면 사례는 열거형 사례와 같습니다. 값이 있는 경우 각 값은 지정된 형식의 단일 값이거나 동일하거나 다른 형식의 여러 필드를 집계하는 튜플일 수 있습니다. 개별 필드에 이름을 지정할 수 있지만 동일한 경우의 다른 필드 이름이 지정되더라도 이름은 선택 사항입니다.
차별된 공용 구조체에 대한 접근성은 기본적으로 .입니다 public
.
예를 들어 셰이프 형식의 다음 선언을 고려합니다.
type Shape =
| Rectangle of width : float * length : float
| Circle of radius : float
| Prism of width : float * float * height : float
앞의 코드는 구분된 공용 구조체 셰이프를 선언합니다. 이 셰이프는 사각형, 원 및 프리즘의 세 가지 사례 중 하나 이상의 값을 가질 수 있습니다. 각 사례에는 서로 다른 필드 집합이 있습니다. 사각형 대/소문자에는 이름 너비와 길이가 있는 두 개의 명명된 필드(형식 float
모두)가 있습니다. 원 케이스에는 명명된 필드 반경이 하나뿐입니다. Prism 사례에는 세 개의 필드가 있으며, 그 중 2개(너비 및 높이)는 명명된 필드입니다. 명명되지 않은 필드를 익명 필드라고 합니다.
다음 예제에 따라 명명된 필드와 익명 필드에 대한 값을 제공하여 개체를 생성합니다.
let rect = Rectangle(length = 1.3, width = 10.0)
let circ = Circle (1.0)
let prism = Prism(5., 2.0, height = 3.0)
이 코드는 초기화에서 명명된 필드를 사용하거나 선언에서 필드의 순서에 의존하여 각 필드에 대한 값을 차례로 제공할 수 있음을 보여 있습니다. 이전 코드에서 생성자 호출 rect
은 명명된 필드를 사용하지만 생성자 호출 circ
은 순서 지정을 사용합니다. 의 생성 prism
과 같이 순서가 지정된 필드와 명명된 필드를 혼합할 수 있습니다.
이 option
형식은 F# 코어 라이브러리에서 단순하게 구분된 공용 구조체입니다. 형식은 option
다음과 같이 선언됩니다.
// The option type is a discriminated union.
type Option<'a> =
| Some of 'a
| None
이전 코드는 형식 Option
이 두 개의 사례가 Some
있는 구분된 공용 구조체이며 None
. 사례에는 Some
형식 매개 변수 'a
로 형식이 표현되는 익명 필드 하나로 구성된 연결된 값이 있습니다. 사례에 None
연결된 값이 없습니다. 따라서 형식은 option
일부 형식의 값이 있거나 값이 없는 제네릭 형식을 지정합니다. 형식 Option
에는 더 일반적으로 사용되는 소문자 형식 별칭 option
도 있습니다.
대/소문자 식별자를 구분된 공용 구조체 형식의 생성자로 사용할 수 있습니다. 예를 들어 다음 코드는 형식의 option
값을 만드는 데 사용됩니다.
let myOption1 = Some(10.0)
let myOption2 = Some("string")
let myOption3 = None
대/소문자 식별자는 패턴 일치 식에도 사용됩니다. 패턴 일치 식에서 개별 사례와 연결된 값에 대한 식별자가 제공됩니다. 예를 들어 다음 코드 x
에서는 형식의 option
사례와 Some
연결된 값이 지정된 식별자입니다.
let printValue opt =
match opt with
| Some x -> printfn "%A" x
| None -> printfn "No value."
패턴 일치 식에서 명명된 필드를 사용하여 구분된 공용 구조체 일치를 지정할 수 있습니다. 이전에 선언된 셰이프 형식의 경우 다음 코드와 같이 명명된 필드를 사용하여 필드 값을 추출할 수 있습니다.
let getShapeWidth shape =
match shape with
| Rectangle(width = w) -> w
| Circle(radius = r) -> 2. * r
| Prism(width = w) -> w
일반적으로 사례 식별자는 공용 구조체의 이름으로 한정하지 않고 사용할 수 있습니다. 이름이 항상 공용 구조체의 이름으로 정규화되도록 하려면 RequireQualifiedAccess 특성을 공용 구조체 형식 정의에 적용할 수 있습니다.
차별된 노조 래핑 해제
F# 구분 공용 구조체에서는 단일 형식 래핑을 위해 do기본 모델링에 자주 사용됩니다. 패턴 일치를 통해 기본 값을 쉽게 추출할 수 있습니다. 단일 사례에 대해 일치 식을 사용할 필요가 없습니다.
let ([UnionCaseIdentifier] [values]) = [UnionValue]
다음은 이에 대한 예입니다.
type ShaderProgram = | ShaderProgram of id:int
let someFunctionUsingShaderProgram shaderProgram =
let (ShaderProgram id) = shaderProgram
// Use the unwrapped value
...
패턴 일치는 함수 매개 변수에서도 직접 허용되므로 다음과 같이 단일 사례를 래프 해제할 수 있습니다.
let someFunctionUsingShaderProgram (ShaderProgram id) =
// Use the unwrapped value
...
구조체 구분 공용 구조체
구분된 공용 구조체를 구조체로 나타낼 수도 있습니다. 이 작업은 특성으로 [<Struct>]
수행됩니다.
[<Struct>]
type SingleCase = Case of string
[<Struct>]
type Multicase =
| Case1 of Case1 : string
| Case2 of Case2 : int
| Case3 of Case3 : double
이러한 형식은 참조 형식이 아니라 값 형식이므로 참조 구분된 공용 구조체와 비교하여 추가 고려 사항이 있습니다.
- 값 형식으로 복사되고 값 형식 의미 체계가 있습니다.
- 다중 시 구조체 구분 공용 구조체에는 재귀 형식 정의를 사용할 수 없습니다.
- 다중 시 구조체 구분 공용 구조체에 고유한 대/소문자 이름을 제공해야 합니다.
개체 계층 대신 차별된 공용 구조체 사용
종종 구분된 공용 구조체를 작은 개체 계층 구조의 더 간단한 대안으로 사용할 수 있습니다. 예를 들어 원, 정사각형 등의 파생 형식이 있는 기본 클래스 대신 Shape
다음과 같은 구분된 공용 구조체를 사용할 수 있습니다.
type Shape =
// The value here is the radius.
| Circle of float
// The value here is the side length.
| EquilateralTriangle of double
// The value here is the side length.
| Square of double
// The values here are the height and width.
| Rectangle of double * double
개체 지향 구현에서 사용하는 것처럼 영역 또는 경계를 계산하는 가상 메서드 대신 분기와 패턴 일치를 사용하여 적절한 수식을 사용하여 이러한 수량을 계산할 수 있습니다. 다음 예제에서는 셰이프에 따라 영역을 계산하는 데 여러 수식이 사용됩니다.
let pi = 3.141592654
let area myShape =
match myShape with
| Circle radius -> pi * radius * radius
| EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
| Square s -> s * s
| Rectangle(h, w) -> h * w
let radius = 15.0
let myCircle = Circle(radius)
printfn "Area of circle that has radius %f: %f" radius (area myCircle)
let squareSide = 10.0
let mySquare = Square(squareSide)
printfn "Area of square that has side %f: %f" squareSide (area mySquare)
let height, width = 5.0, 10.0
let myRectangle = Rectangle(height, width)
printfn "Area of rectangle that has height %f and width %f is %f" height width (area myRectangle)
출력은 다음과 같습니다.
Area of circle that has radius 15.000000: 706.858347
Area of square that has side 10.000000: 100.000000
Area of rectangle that has height 5.000000 and width 10.000000 is 50.000000
트리 데이터 구조에 대해 차별된 공용 구조체 사용
차별된 공용 구조체는 재귀적일 수 있으며, 이는 노조 자체가 하나 이상의 사례 유형에 포함될 수 있음을 의미합니다. 재귀 구분된 공용 구조체를 사용하여 프로그래밍 언어로 식을 모델링하는 데 사용되는 트리 구조를 만들 수 있습니다. 다음 코드에서는 재귀 구분된 공용 구조체를 사용하여 이진 트리 데이터 구조를 만듭니다. 공용 구조체는 정수 값과 왼쪽 및 오른쪽 하위 트리Tip
가 있는 노드이고 트리를 종료하는 두 가지 사례Node
로 구성됩니다.
type Tree =
| Tip
| Node of int * Tree * Tree
let rec sumTree tree =
match tree with
| Tip -> 0
| Node(value, left, right) -> value + sumTree (left) + sumTree (right)
let myTree =
Node(0, Node(1, Node(2, Tip, Tip), Node(3, Tip, Tip)), Node(4, Tip, Tip))
let resultSumTree = sumTree myTree
이전 코드 resultSumTree
에서 값은 10입니다. 다음 그림에서는 에 대한 myTree
트리 구조를 보여 줍니다.
트리의 노드가 이질적인 경우 차별된 공용 구조체가 잘 작동합니다. 다음 코드에서 이 형식 Expression
은 숫자와 변수의 추가 및 곱셈을 지원하는 간단한 프로그래밍 언어로 식의 추상 구문 트리를 나타냅니다. 일부 공용 구조체 사례는 재귀적이지 않으며 숫자() 또는 변수(Number
Variable
)를 나타냅니다. 다른 경우는 재귀적이며 피연산자도 식인 연산(Add
및 Multiply
)을 나타냅니다. 함수는 Evaluate
일치 식을 사용하여 구문 트리를 재귀적으로 처리합니다.
type Expression =
| Number of int
| Add of Expression * Expression
| Multiply of Expression * Expression
| Variable of string
let rec Evaluate (env: Map<string, int>) exp =
match exp with
| Number n -> n
| Add(x, y) -> Evaluate env x + Evaluate env y
| Multiply(x, y) -> Evaluate env x * Evaluate env y
| Variable id -> env[id]
let environment = Map [ "a", 1; "b", 2; "c", 3 ]
// Create an expression tree that represents
// the expression: a + 2 * b.
let expressionTree1 = Add(Variable "a", Multiply(Number 2, Variable "b"))
// Evaluate the expression a + 2 * b, given the
// table of values for the variables.
let result = Evaluate environment expressionTree1
이 코드가 실행되면 값 result
은 5입니다.
멤버
차별된 노조에 대한 구성원을 정의할 수 있습니다. 다음 예제에서는 속성을 정의하고 인터페이스를 구현하는 방법을 보여줍니다.
open System
type IPrintable =
abstract Print: unit -> unit
type Shape =
| Circle of float
| EquilateralTriangle of float
| Square of float
| Rectangle of float * float
member this.Area =
match this with
| Circle r -> Math.PI * (r ** 2.0)
| EquilateralTriangle s -> s * s * sqrt 3.0 / 4.0
| Square s -> s * s
| Rectangle(l, w) -> l * w
interface IPrintable with
member this.Print () =
match this with
| Circle r -> printfn $"Circle with radius %f{r}"
| EquilateralTriangle s -> printfn $"Equilateral Triangle of side %f{s}"
| Square s -> printfn $"Square with side %f{s}"
| Rectangle(l, w) -> printfn $"Rectangle with length %f{l} and width %f{w}"
일반적인 특성
다음 특성은 일반적으로 차별된 공용 구조체에서 볼 수 있습니다.
[<RequireQualifiedAccess>]
[<NoEquality>]
[<NoComparison>]
[<Struct>]
참고 항목
.NET