Perl 6 中的 Roles Vs. Protocol
Protocol 在 Swift 中是一組方法和屬性的集合, 可用於程式碼複用。 Perl 6 中有與之類似的結構, 叫做 Role
, 下面轉換一個 Swift 的 Protocol 為 Perl 6 的 Role, 把部門人員的相關資訊列印為一個表格:
Protocol in Swift
import UIKit
func padding(amount: Int) -> String {
var paddingString = ""
for _ in 0..<amount {
paddingString += " "
}
return paddingString
}
// 協議
protocol TabularDataSource {
var numberOfRows: Int { get }
var numberOfColumns: Int { get }
func labelForRow(row: Int) -> String // 行標籤
func labelForColumn(column: Int) -> String // 列標籤
func itemForRow(row: Int, column: Int) -> Int // 表格中的單元格
}
struct Person {
let name: String
let age: Int
let yearsOfExperience: Int
}
// 讓 **Department** 遵守 **TabularDataSource**協議
struct Department: TabularDataSource {
let name: String
var people = [Person]()
init(name: String) {
self.name = name
}
mutating func addPerson(person: Person) {
people.append(person)
}
// 實現協議中宣告的屬性和方法
var numberOfRows: Int {
return people.count
}
var numberOfColumns: Int {
return 2
}
func labelForRow(row: Int) -> String {
return people[row].name
}
func labelForColumn(column: Int) -> String {
switch column {
case 0: return "Age"
case 1: return "Years of Experence"
default: fatalError("Invalid column!")
}
}
func itemForRow(row: Int, column: Int) -> Int {
let person = people[row] // 指定的行
switch column {
case 0: return person.age
case 1: return person.yearsOfExperience
default:fatalError("Invalid column!")
}
}
}
var deparment = Department(name: "Engineering")
deparment.addPerson(Person(name: "Joe", age: 30, yearsOfExperience: 6))
deparment.addPerson(Person(name: "Karen", age: 40, yearsOfExperience: 18))
deparment.addPerson(Person(name: "Fred", age: 50, yearsOfExperience: 20))
// 傳入一個資料來源
func printTable(dataSource: TabularDataSource) {
let rowLabels = (0 ..< dataSource.numberOfRows).map { dataSource.labelForRow($0) }
let columnLabels = (0 ..< dataSource.numberOfColumns).map { dataSource.labelForColumn($0) }
// 建立一個陣列儲存每個行標籤的寬度
let rowLabelWidths = rowLabels.map { $0.characters.count }
// 限定行標籤的最大長度
guard let maxRowLabelWidth = rowLabelWidths.maxElement() else {
return
}
// 建立第一行, 包含列標題
var firstRow = padding(maxRowLabelWidth) + " |"
// 跟蹤每列的寬度
var columnWidths = [Int]()
for columnLabel in columnLabels {
let columnHeader = " \(columnLabel) |"
firstRow += columnHeader
columnWidths.append(columnHeader.characters.count)
}
print(firstRow)
for i in 0 ..< dataSource.numberOfRows {
let paddingAmount = maxRowLabelWidth - rowLabelWidths[i]
var out = rowLabels[i] + padding(paddingAmount) + " |"
for j in 0 ..< dataSource.numberOfColumns {
let item = dataSource.itemForRow(i, column: j)
let itemString = " \(item) |"
let paddingAmount = columnWidths[j] - itemString.characters.count
out += padding(paddingAmount) + itemString
}
print(out)
}
}
printTable(deparment)
其中的計算屬性在 Perl 6 中可以使用重寫屬性的方法來完成。
Role in Perl 6
use v6;
sub padding(Int $amount) {
my $paddingString = "";
$paddingString ~= " " for 0 ..^ $amount;
return $paddingString;
}
# 宣告一個介面, 只定義了方法和屬性, 沒有做實現
role TabularDataSource {
has $.numberOfRows is rw;
has $.numberOfColumns is rw;
method labelForRow(Int $row) { ... }
method labelForColumn(Int $column) { ... }
method itemForRow(Int $row, Int $column) { ... }
}
class Person {
has Str $.name;
has Int $.age;
has Int $.yearsOfExperience;
}
class Department does TabularDataSource {
has $.name;
has @.people;
method new(Str $name) {
self.bless(name => $name);
}
# 實現介面中的方法
# 重寫方法 has $.numberOfRows 其實是 has $!numberOfRows 加上 method numberOfRows() { ... } 方法。
method numberOfRows() {
return @!people.elems;
}
method numberOfColumns() {
return 2;
}
method addPerson(Person $person) is rw {
@!people.append($person);
}
# 如果類遵守了某個 role 但是未實現其中的方法, 則會報錯如下:
# Method 'labelForRow' must be implemented by Department because it is required by a role
method labelForRow(Int $row) {
return @!people[$row].name;
}
method labelForColumn(Int $column) {
given $column {
when 0 { return "Age" }
when 1 { return "Years of Experence" }
default { die("Invalid column!")}
}
}
method itemForRow(Int $row, Int $column) {
my $person = @!people[$row];
given $column {
when 0 { return $person.age }
when 1 { return $person.yearsOfExperience }
default { die("Invalid column") }
}
}
}
my $department = Department.new("Engineering");
$department.addPerson(Person.new(name => "Joe", age => 30, yearsOfExperience => 6));
$department.addPerson(Person.new(name => "Karen", age => 40, yearsOfExperience => 18));
$department.addPerson(Person.new(name => "Fred", age => 50, yearsOfExperience => 20));
sub printTable(TabularDataSource $dataSource) {
my @rowLabels = (0 ..^ $dataSource.numberOfRows ).map: { $dataSource.labelForRow($_)};
my @columnLabels = (0 ..^ $dataSource.numberOfColumns).map: {$dataSource.labelForColumn($_)};
my @rowLabelWidths = @rowLabels.map: {$_.chars};
my $maxRowLabelWidth = @rowLabelWidths.max // return;
my $firstRow = padding($maxRowLabelWidth) ~ " |";
my @columnWidths;
for @columnLabels -> $columnLabel {
my $columnHeader = " $columnLabel |";
$firstRow ~= $columnHeader;
@columnWidths.append($columnHeader.chars);
}
say($firstRow);
for 0 ..^ $dataSource.numberOfRows -> $i {
my $paddingAmount = $maxRowLabelWidth - @rowLabelWidths[$i];
my $out = @rowLabels[$i] ~ padding($paddingAmount) ~ " |";
for 0 ..^ $dataSource.numberOfColumns -> $j {
my $item = $dataSource.itemForRow($i, $j);
my $itemString = " $item |";
my $paddingAmount = @columnWidths[$j] - $itemString.chars;
$out ~= padding($paddingAmount) ~ $itemString;
}
say($out);
}
}
printTable($department);
role 中的 { ... }
是 yadayada操作符, 起佔位作用, 表示方法會在別處實現。類中的方法同樣也可以這樣宣告。
最後輸出:
| Age | Years of Experence |
Joe | 30 | 6 |
Karen | 40 | 18 |
Fred | 50 | 20 |
相關文章
- [譯][Perl 6] 5to6-perlfunc
- [譯][Perl 6] 5to6-nutshell
- Dubbo on x-protocol——SOFAMesh中的x-protocol示例演示Protocol
- Protocol Buffers 在 iOS 中的使用ProtocoliOS
- Airflow vs. Luigi vs. Argo vs. MLFlow vs. KubeFlowAIUIGo
- SAP Business Technology Platform 上 Roles,Roles collection 和 Scopes 的關聯關係Platform
- 不求甚解--詳解ansible-playbook中roles的用法
- perl的logwrapperAPP
- 2.2.3.1 Common Roles in a CDB
- ansible-roles-06
- perl
- HashSet vs. TreeSet vs. LinkedHashSet
- 2.2.4.5 Grants of Privileges and Roles: Scenario
- 2.2.4.3.2 Roles and Privileges Granted Commonly
- 2.2.4.2.2 Roles and Privileges Granted Locally
- 【Perl程式設計-6】正規表示式--替換+轉化程式設計
- 2.2.4.3 Roles and Privileges Granted Commonly in a CDB
- 2.2.4.2 Privileges and Roles Granted Locally in a CDB
- Perl語言學習(四)Perl控制結構
- Perl&LWP
- perl指令碼指令碼
- 使用perl cpan
- perl 安裝
- [轉]Shell向Perl指令碼中傳遞變數的方法指令碼變數
- protocol bufferProtocol
- No appropriate protocolAPPProtocol
- 為 protocol 中屬性新增預設值Protocol
- Protocol Buffers 系列 (1) - 什麼是Protocol Buffers?Protocol
- Perl語法的基本規則
- PERL 5.8的反序列化
- 講 perl debug 的不錯文章
- 使用perl比較mysql的版本MySql
- perl+xml+iniXML
- Perl Catalyst 倒出 ExcelExcel
- Perl常用語法
- 搞懂:資料科學vs.機器學習vs.資料分析vs.商業分析資料科學機器學習
- Ansible vs. TerraformORM
- Navigating Kubernetes Certification: CKAD vs. CKA vs. CKS, Including KCNA and KCSA
- TensorFlow中結構化資料工具Protocol BufferProtocol