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)
- [譯][Perl 6] 5to6-perlfunc
- [譯][Perl 6] 5to6-nutshell
- Perl 6 簡單的並行並行
- Perl 6 網頁抓取網頁
- Perl 6 語言概述
- perl6學習
- Perl中FTP的使用FTP
- Dubbo on x-protocol——SOFAMesh中的x-protocol示例演示Protocol
- Roles in BW ProjectsProject
- [譯]Perl中的陣列陣列
- Protocol Buffers 在 iOS 中的使用ProtocoliOS
- SAP Business Technology Platform 上 Roles,Roles collection 和 Scopes 的關聯關係Platform
- perl 中glob函式的使用函式
- 6,雜湊(perl語言筆記)筆記
- Airflow vs. Luigi vs. Argo vs. MLFlow vs. KubeFlowAIUIGo
- Swift中熟悉的陌生人:Protocol(一)SwiftProtocol
- perl中my與local的區別
- Perl6 檔案相關內容
- ansible的roles介紹和實戰
- perl中呼叫系統命令
- 也談Hypertext Transfer Protocol中Transfer的譯法Protocol
- MVC vs. MVP vs. MVVMMVCMVPMVVM
- perl Statistics::Descriptive Perl 的統計模組
- Oracle Roles學習與測試Oracle
- ansible的roles介紹和實戰薦
- perl正規表示式中的特殊變數變數
- 為 protocol 中屬性新增預設值Protocol
- Protocol Buffers 學習(6):檔案 | 欄位選項介紹Protocol
- 《Modern Perl》前言--包含了Perl的安裝使用
- Larry Wall 專訪:語言學、Perl 6 的設計和釋出
- git revert .vs. git reset .vs. git rebaseGit
- String.format VS. StrSubstitutor VS. NamedParameterJdbcTemplateORMJDBC
- perl中如何執行外部命令
- 搞懂:資料科學vs.機器學習vs.資料分析vs.商業分析資料科學機器學習
- protocol bufferProtocol
- Objective-C 中的協議(@protocol)和介面(@interface)的區別Object協議Protocol
- perl的安裝