gpt4 book ai didi

swift - 有什么方法可以在不使用泛型的情况下编写我的协议(protocol),或者使用关联类型的其他解决方法?

转载 作者:行者123 更新时间:2023-11-28 13:37:58 25 4
gpt4 key购买 nike

我有一个协议(protocol) ScaleDetails,我希望几个不同的 Scale 结构符合(即 MajorScaleDiminishedScale 等)。然后我想要一个不同的协议(protocol),ComboChord,它有一个类型为 ScaleDetails 的变量 scale,这将是一个不同的规模取决于另一个别处变量。问题是我无法将 ComboChord 中的 scale var 分配给类型 ScaleDetails 因为我不知道如何在没有使用关联类型。

每个不同的比例使用不同的模式枚举(例如 Mode.SevenDeg 用于 MajorScaleMode.TwoDeg 用于 DiminishedScale)。每个比例都有返回该特定比例结构的一个或多个实例的函数。因此,如果不在我的 ScaleDetails 协议(protocol)中使用泛型,我看不到前进的方向。如果可能的话,我试图在不使用类的情况下编写它,但如果有必要,我愿意使用它们。我也确实在努力避免对我的比例进行类型转换,因为我不想每次调用它时都必须列出每个比例可能性。我该如何解决这个问题?

ScaleDetails 协议(protocol)

protocol ScaleDetails {
associatedtype ScaleMode where ScaleMode: RawRepresentable
associatedtype T
//...
var root: Root { get set }
var mode: ScaleMode { get set }
//...
init(_ root: KeyName.Root, mode: ScaleMode)

func translated(by offset: Int) -> T

func enharmSwapped() -> T
//...
mutating func switchMode(mode: ScaleMode)

func getParallelModes(root: KeyName.Root) -> [T]
func getParentModes() -> [T]
}

ComboChord 协议(protocol)

protocol ComboChord {
var scale: ScaleDetails // doesn't work

static var validCombos: [[Int]] { get }

var quality: Suffix { get }
var uprStrNotes: [Int] { get }
/*
error: "Protocol can only be used as a generic constraint
because it has Self or associatedType requirements"
*/
}

模式枚举

enum Mode {

enum TwoDeg: Int, CaseIterable, ModeProtocol {
case one = 0, two

//...
}

enum SevenDeg: Int, CaseIterable, ModeProtocol {
case one = 0, two, three, four, five, six, seven

//...
}
}

大尺度

struct MajorScale: ScaleDetails {
var root: Root
var mode: Mode.SevenDeg

//...

init(_ root: KeyName.Root, mode: Mode.SevenDeg = .one) {
self.root = Root(root)
self.mode = mode
self.enharm = root.r.enharm
}

func translated(by offset: Int) -> MajorScale {
//...do things to the scale

return MajorScale(newRootKey, mode: mode)
}

//...
mutating func switchMode(mode: Mode.SevenDeg) {
self.mode = mode
}

//...

func enharmSwapped() -> MajorScale {
//...do things to the scale

return MajorScale(newRootKey, mode: mode)
}

func getParallelModes(root: KeyName.Root) -> [MajorScale] {
return Mode.SevenDeg.allCases.map {MajorScale(root, mode: $0)}
}

func getParentModes() -> [MajorScale] {
//...code to get array of scales
return parentModes
}
}

缩小比例

struct DiminishedScale: ScaleDetails {
var root: Root
var mode: Mode.TwoDeg

//...

init(_ root: KeyName.Root, mode: Mode.TwoDeg = .one) {
self.root = Root(root)
self.mode = mode
self.enharm = root.r.enharm
}

func translated(by offset: Int) -> DiminishedScale {
//...do things to the scale

return MajorScale(newRootKey, mode: mode)
}

//...
mutating func switchMode(mode: Mode.TwoDeg) {
self.mode = mode
}

//...

func enharmSwapped() -> DiminishedScale {
//...do things to the scale

return MajorScale(newRootKey, mode: mode)
}

func getParallelModes(root: KeyName.Root) -> [DiminishedScale] {
return Mode.TwoDeg.allCases.map {DiminishedScale(root, mode: $0)}
}

func getParentModes() -> [DiminishedScale] {
//...code to get array of scales
return parentModes
}
}

KeyName.Root

enum KeyName: String, CaseIterable {
case c = "C"
case d = "D"
case e = "E"
case f = "F"
case g = "G"
case a = "A"
case b = "B"

case cB = "C\u{266D}"
case dB = "D\u{266D}"
case eB = "E\u{266D}"
case fB = "F\u{266D}"
case gB = "G\u{266D}"
case aB = "A\u{266D}"
case bB = "B\u{266D}"

case cSh = "C\u{266F}"
case dSh = "D\u{266F}"
case eSh = "E\u{266F}"
case fSh = "F\u{266F}"
case gSh = "G\u{266F}"
case aSh = "A\u{266F}"
case bSh = "B\u{266F}"

case c_bb = "C\u{266D}\u{266D}"
case d_bb = "D\u{266D}\u{266D}"
case e_bb = "E\u{266D}\u{266D}"
case f_bb = "F\u{266D}\u{266D}"
case g_bb = "G\u{266D}\u{266D}"
case a_bb = "A\u{266D}\u{266D}"
case b_bb = "B\u{266D}\u{266D}"

case cX = "Cx"
case dX = "Dx"
case eX = "Ex"
case fX = "Fx"
case gX = "Gx"
case aX = "Ax"
case bX = "Bx"

enum Root {
case c, d, e, f, g, a, b
case cB, dB, eB, fB, gB, aB, bB
case cSh, dSh, eSh, fSh, gSh, aSh, bSh

var r: KeyName {
switch self {
case .c:
return .c
case .d:
return .d
case .e:
return .e
case .f:
return .f
case .g:
return .g
case .a:
return .a
case .b:
return .b
case .cB:
return .cB
case .dB:
return .dB
case .eB:
return .eB
case .fB:
return .fB
case .gB:
return .gB
case .aB:
return .aB
case .bB:
return .bB
case .cSh:
return .cSh
case .dSh:
return .dSh
case .eSh:
return .eSh
case .fSh:
return .fSh
case .gSh:
return .gSh
case .aSh:
return .aSh
case .bSh:
return .bSh
}
}

init(_ key: KeyName) {
switch key {
case .c:
self = .c
case .d:
self = .d
case .e:
self = .e
case .f:
self = .f
case .g:
self = .g
case .a:
self = .a
case .b:
self = .b
case .cB:
self = .cB
case .dB:
self = .dB
case .eB:
self = .eB
case .fB:
self = .fB
case .gB:
self = .gB
case .aB:
self = .aB
case .bB:
self = .bB
case .cSh:
self = .cSh
case .dSh:
self = .dSh
case .eSh:
self = .eSh
case .fSh:
self = .fSh
case .gSh:
self = .gSh
case .aSh:
self = .aSh
case .bSh:
self = .bSh
default:
self = .c
}
}
}
//...
}

struct Root: Note {
var noteName: String {
return key.name
}

var rootKey: KeyName.Root
var noteNum: NoteNum
var num: Int {return noteNum.num}
var enharm: Enharmonic

var degName: (name: DegName.Name, short: DegName.Short, long: DegName.Long) {
return (name: DegName.Name(.root), short: DegName.Short(.root), long: DegName.Long(.root))
}

var key: KeyName

init(noteNum: NoteNum = .zero, enharm: Enharmonic = .flat) {
self.noteNum = noteNum
self.enharm = enharm

var ks: KeySwitch {
return KeySwitch(enharm: enharm)
}

var rs: RootSwitch {
return RootSwitch(enharm: enharm)
}

switch noteNum {
case .zero:
self.key = ks.pickKey(.c, .bSh)
self.rootKey = rs.pickRoot(.c, .bSh)
case .one:
self.key = ks.pickKey(.dB, .cSh)
self.rootKey = rs.pickRoot(.dB, .cSh)
case .two:
self.key = .d
self.rootKey = .d
case .three:
self.key = ks.pickKey(.eB, .dSh)
self.rootKey = rs.pickRoot(.eB, .dSh)
case .four:
self.key = ks.pickKey(.fB, .e)
self.rootKey = rs.pickRoot(.fB, .e)
case .five:
self.key = ks.pickKey(.f, .eSh)
self.rootKey = rs.pickRoot(.f, .eSh)
case .six:
self.key = ks.pickKey(.gB, .fSh)
self.rootKey = rs.pickRoot(.gB, .fSh)
case .seven:
self.key = .g
self.rootKey = .g
case .eight:
self.key = ks.pickKey(.aB, .gSh)
self.rootKey = rs.pickRoot(.aB, .gSh)
case .nine:
self.key = .a
self.rootKey = .a
case .ten:
self.key = ks.pickKey(.bB, .aSh)
self.rootKey = rs.pickRoot(.bB, .aSh)
case .eleven:
self.key = ks.pickKey(.cB, .b)
self.rootKey = rs.pickRoot(.cB, .b)
}
}

init(_ key: KeyName.Root) {
self.key = key.r
self.rootKey = key
self.noteNum = self.key.noteNum
self.enharm = self.key.enharm
}

mutating func kSW(ks: KeySwitch) {
switch noteNum {
case .zero:
self.key = ks.pickKey(.c, .bSh)
case .one:
self.key = ks.pickKey(.dB, .cSh)
case .two:
self.key = .d
case .three:
self.key = ks.pickKey(.eB, .dSh)
case .four:
self.key = ks.pickKey(.fB, .e)
case .five:
self.key = ks.pickKey(.f, .eSh)
case .six:
self.key = ks.pickKey(.gB, .fSh)
case .seven:
self.key = .g
case .eight:
self.key = ks.pickKey(.aB, .gSh)
case .nine:
self.key = .a
case .ten:
self.key = ks.pickKey(.bB, .aSh)
case .eleven:
self.key = ks.pickKey(.cB, .b)
}
}

mutating func swapEnharm() {
enharm = enharm == .flat ? .sharp : .flat
kSW(ks: KeySwitch(enharm: enharm))
rootKey = KeyName.Root(key)
}

func enharmSwapped() -> Root {
return Root(noteNum: noteNum, enharm: enharm == .flat ? .sharp : .flat)
}
}

细节和弦

(大幅缩减了长度……原来大约有 1400 行)

struct DetailChord {
enum DCType {
case dom7, ma7, mi7, mi7b5, dim7, error
}

init(resultChord: ResultChord?, verdict: Verdict = .goodToGo) {
self.verdict = verdict
self.dRC = resultChord
if let rc = dRC {
switch rc.baseChord.lowerQual {
case .dom7:
dct = .dom7
case .ma7:
dct = .ma7
case .mi7:
dct = .mi7
case .mi7_b5:
dct = .mi7b5
case .dim7:
dct = .dim7
}
} else {
dct = .error
}
}

var dct: DCType

var dRC: ResultChord?

var verdict: Verdict

var validCombos: [[[Int]]] {
switch dct {
case .dom7:
return Dom7.validCombos
case .ma7:
return Maj7.validCombos
case .mi7:
return Min7.validCombos
case .mi7b5:
return Min7_b5.validCombos
case .dim7:
return Dim7.validCombos
default:
return [[[]]]
}
}

var tension: [[Int]] {
switch dct {
case .dom7:
return Dom7.tension
case .ma7:
return Maj7.tension
case .mi7:
return Min7.tension
case .mi7b5:
return Min7_b5.tension
case .dim7:
return Dim7.tension
default:
return [[]]
}
}

func qualSwitcher(validCombos: [[[Int]]], degrees: [Int]) -> Int {
var validCombosIndex = Int()
for (index, combos) in validCombos.enumerated() {
if combos.contains(degrees) {
validCombosIndex = index
break
}
}

return validCombosIndex
}

var chord: ComboChord {
mutating get {
if let rc = dRC {
let degrees = rc.degrees
let degreesUnsorted = rc.degreesUnsorted
let baseChord = rc.baseChord
let degSet = rc.degSet

var validCombosIndex = Int()

func tensionOrGoodToGo(getComboChord: GetComboChord) -> ComboChord {
if !tension.contains(degrees) { // good to go!
verdict = .goodToGo
validCombosIndex = qualSwitcher(validCombos: validCombos, degrees: degrees)
return getComboChord(degSet, validCombosIndex)
} else { // tension!
verdict = .tension
if let tensionQual = rc.baseChord.qualSuffix as? Suffix.Lower {
return TensionChord(tensionQual, rc.degreesUnsorted)
} else {
return ErrorChord()
}
}
}

switch dct {
case .dom7:
return tensionOrGoodToGo(getComboChord: Dom7.getComboChord(degSet:validCombosIndex:))
case .ma7:
return tensionOrGoodToGo(getComboChord: Maj7.getComboChord(degSet:validCombosIndex:))
case .mi7:
return tensionOrGoodToGo(getComboChord: Min7.getComboChord(degSet:validCombosIndex:))
case .mi7b5:
return tensionOrGoodToGo(getComboChord: Min7_b5.getComboChord(degSet:validCombosIndex:))
case .dim7:
return tensionOrGoodToGo(getComboChord: Dim7.getComboChord(degSet:validCombosIndex:))
case .error:
return ErrorChord()
}
} else {
print("rc not found!")
dct = .error
return ErrorChord()
}
}
}

struct Dom7: DetailChordType {
static let matches = Mixolydian.validCombos + LydianDom.validCombos + HalfWholeDim.validCombos + AltP5.validCombos + MelodicMinor_Chord.validCombos + HexatonicSh9Sh11_Chord.validCombos + HalfWholeDimFlat13_Chord.validCombos

static let validCombos: [[[Int]]] = [Mixolydian.validCombos, LydianDom.validCombos, HalfWholeDim.validCombos, AltP5.validCombos, MelodicMinor_Chord.validCombos, HexatonicSh9Sh11_Chord.validCombos, HalfWholeDimFlat13_Chord.validCombos]

static let tension = [[0, 1, 4, 5, 7, 8, 10], [0, 4, 7, 8, 10, 11], [0, 4, 5, 7, 9, 10], [0, 2, 4, 7, 10, 11], [0, 2, 4, 5, 7, 10], [0, 3, 4, 6, 7, 10, 11], [0, 2, 4, 5, 7, 9, 10], [0, 4, 7, 10, 11], [0, 4, 5, 7, 8, 10], [0, 3, 4, 7, 8, 10, 11], [0, 1, 4, 5, 7, 10], [0, 2, 4, 6, 7, 10, 11], [0, 1, 4, 5, 7, 9, 10], [0, 3, 4, 7, 10, 11], [0, 2, 4, 5, 7, 8, 10], [0, 4, 5, 7, 8, 10, 11], [0, 2, 4, 7, 8, 10, 11], [0, 2, 4, 5, 7, 10, 11], [0, 3, 4, 5, 7, 10], [0, 4, 5, 7, 10], [0, 4, 6, 7, 10, 11], [0, 4, 7, 9, 10, 11], [0, 1, 4, 6, 7, 10, 11]]

static let tensionTones = [5, 11]

static func getComboChord(degSet: Set<Int>, validCombosIndex: Int) -> ComboChord {
switch validCombosIndex {
case 0: // mixolydian
switch degSet {
case let degs where degs.isSuperset(of: Dom7.Mixolydian.XIII.uprStrNotes): // 13
return Dom7.Mixolydian.xiii
// sus4/sus2 on 2nd, sus2 on 5th, min or sus 4 triad on maj6
case let degs where degs.isSuperset(of: Dom7.Mixolydian.Nine.uprStrNotes): // 9
// sus2 on root, min or sus4 triad on p5
return Dom7.Mixolydian.nine
default: // 7
//maj triad on root, dim triad on 3rd
return Dom7.Mixolydian.seven
}
case 1: // lydian dominant
// similar structure to case 0
case 2: // half-whole dim
// similar structure to case 0
case 3:
// similar structure to case 0
case 4: // 5th mode melodic minor
// similar structure to case 0
case 5: // hexatonicSh9Sh11
// similar structure to case 0
default: // half-whole dim(b13)
// similar structure to case 0
}
}

var chordType: ComboChord = Mixolydian.seven

enum Mixolydian: ComboChord {

case seven, nine, xiii

var scale: ScaleDetails {
switch self {
default:
return Major(mode: .five, modeOffset: 0)
}
}

static let validCombos: [[Int]] = Seven.validCombos + Nine.validCombos + XIII.validCombos

struct Seven {
static let validCombos = [[0, 4, 7, 10]]
static let uprStrNotes: [Int] = []
}

struct Nine {
static let validCombos: [[Int]] = [[0, 2, 4, 7, 10]]
static let uprStrNotes: [Int] = [2]
}

struct XIII {
static let validCombos: [[Int]] = [[0, 2, 4, 7, 9, 10], [0, 4, 7, 9, 10]]
static let uprStrNotes: [Int] = [9]
}

var quality: Suffix {
switch self {
case .seven:
return .sev
case .nine:
return .nine
case .xiii:
return .xiii
}
}

var uprStrNotes: [Int] {
switch self {
case .seven:
return Seven.uprStrNotes
case .nine:
return Nine.uprStrNotes
case .xiii:
return XIII.uprStrNotes
}
}
}

enum LydianDom: ComboChord {
// same structure as Mixolydian
}

enum HalfWholeDim: ComboChord {
// same structure as Mixolydian
}

enum AltP5: ComboChord {
// same structure as Mixolydian
}

enum HexatonicSh9Sh11_Chord: ComboChord {
// same structure as Mixolydian
}

enum MelodicMinor_Chord: ComboChord {
// same structure as Mixolydian
}

enum HalfWholeDimFlat13_Chord: ComboChord {
// same structure as Mixolydian
}
}

struct Maj7: DetailChordType {
// same structure as Dom7
}

struct Min7: DetailChordType {
// same structure as Dom7
}

struct Min7_b5: DetailChordType {
// same structure as Dom7
}

struct Dim7: DetailChordType {
// same structure as Dom7
}
}

最佳答案

不确定它是否适合您的使用,但也许您也可以使 ComboChord 通用

protocol ComboChord {
associatedtype Scale: ScaleDetails
var scale: Scale { get }
}

然后像这样使用它

struct Chord: ComboChord {

var scale: DiminishedScale

}

关于swift - 有什么方法可以在不使用泛型的情况下编写我的协议(protocol),或者使用关联类型的其他解决方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56381158/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com