各言語におけるイミュータブルな構造体
各言語におけるイミュータブルな構造体
フィールドに再代入不可能な構造体
レコード型・NamedTuple
Python
NamedTuple
code:python
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(10, 20)
# p.x = 30 # ランタイムエラー。再代入できない
コンパイルエラーじゃないのがね...
dataclassをimmutableにできる
code:python
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
point = Point(3, 4)
# point.x = 5 # エラーになる
TypeScript
code:ts
type Point = { readonly x: number; readonly y: number };
const p: Point = { x: 10, y: 20 };
// p.x = 30; // コンパイルエラー
Swift
Tuple
Tupleに名前をつけられる
let 再代入不可能
code:swift
let point = (x: 10, y: 20)
// point.x = 30 // コンパイルエラー
var p2 = (x: 10, y: 20)
p2.x = 30 // ok
https://swift.codelly.dev/guide/基本の型/Tuple型.html
名前がついてないので取り回しが悪そう
名前をつける
code:swift
typealias Point = (x: Int, y: Int)
typealias Point = (x: Int, y: Int)
var p = (x:10, y:20)
p.x = 100
letかvarかで再代入可能か決まるから、よくない
素直に構造体で
code:swift
struct Point {
let x: Int
let y: Int
}
var point = Point(x: 10, y: 20)
point.x = 100
print(point.x) // 10
Java
Record type
code:java
public record Point(int x, int y) {}
Point p = new Point(10, 20);
// p.x = 30; // コンパイルエラー
Kotlin
data class
valを使うと不変になる
code:kt
data class Point(val x: Int, val y: Int)
val p = Point(10, 20)
// p.x = 30 // コンパイルエラー
Scala
case class
code:scala
case class Point(x: Int, y: Int)
val p = Point(10, 20)
// p.x = 30 // コンパイルエラー: reassignment to val
Go
ない?
そんな
Goで実現するには
Getterのみを定義する
code:go
type Point struct {
x int
y int
}
func NewPoint(x, y int) Point {
return Point{x: x, y: y}
}
func (p Point) X() int { return p.x }
func (p Point) Y() int { return p.y }
参考
https://stackoverflow.com/questions/47632706/immutable-struct-in-golang
Rust
mutをつけずに宣言した構造体はイミュータブル
code:rust
struct Point {
x: i32,
y: i32,
}
let p1 = Point { x: 3, y: 4 }; // 不変な構造体のインスタンス
p1.x = 5; // コンパイルエラー
let mut p2 = Point { x: 3, y: 4 };
p2.x = 5; // エラーは発生しない
感想
Scala/Kotlin/Java 1行で定義できていい
Pythonは結局動的型付け言語なので理想的ではないけど、ないよりマシだしすっきりかけていい
Goはボイラープレートが増えてしんどい